Skip to content

Commit 6bdf49f

Browse files
committed
Run cbuild async
1 parent 423b0cb commit 6bdf49f

4 files changed

Lines changed: 33 additions & 28 deletions

File tree

src/solutions/solution-converter.test.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ describe('SolutionConverter', () => {
208208
expect(mockCsolutionService.convertSolution).toHaveBeenCalledTimes(1);
209209
});
210210
it('sends output to the output channel', async () => {
211+
// Explicitly mock convertSolution to return success: true
212+
mockCsolutionService.convertSolution.mockResolvedValue({ success: true });
213+
mockCsolutionService.getLogMessages.mockResolvedValue({ errors: [], warnings: [], info: [], success: true });
211214
await fireAndWaitForConversion();
212215

213216
const outputChannel = outputChannelProvider.mockGetCreatedChannelByName(manifest.CMSIS_SOLUTION_OUTPUT_CHANNEL);
@@ -216,9 +219,9 @@ describe('SolutionConverter', () => {
216219
expect.stringContaining('⚙️ Converting solution...'),
217220
expect.stringContaining('Check for missing packs...'),
218221
expect.stringContaining('Convert solution...'),
219-
expect.stringContaining('Setup database...'),
220222
expect.stringContaining('Get log messages...'),
221223
expect.stringContaining('✅ Convert solution completed'),
224+
expect.stringContaining('Setup database...'),
222225
]);
223226
expect(completedListener).toHaveBeenCalledTimes(1);
224227
});
@@ -365,7 +368,7 @@ describe('SolutionConverter', () => {
365368

366369
it('get cbuild west output and set diagnostics accordingly', async () => {
367370
mockCsolutionService.convertSolution.mockResolvedValue({ success: true });
368-
mockCsolutionService.getLogMessages.mockResolvedValue({ success: true });
371+
mockCsolutionService.getLogMessages.mockResolvedValue({ errors: [], warnings: [], info: [], success: true });
369372
let mockRunCbuildSetup = jest.spyOn(compileCommandsGenerator, 'runCbuildSetup').mockResolvedValue([true, [
370373
'warning cbuild: missing ZEPHYR_BASE environment variable',
371374
'error cbuild: exec: "west": executable file not found in $PATH',
@@ -377,23 +380,23 @@ describe('SolutionConverter', () => {
377380
jest.spyOn(vscodeUtils, 'getWorkspaceFolder').mockReturnValue('workspace/folder');
378381

379382
await fireAndWaitForConversion();
380-
await waitTimeout();
381-
expect(mockRunCbuildSetup).toHaveBeenCalledTimes(1);
383+
384+
// Convert event should NOT have cbuild output (convert-only payload)
382385
expect(completedListener).toHaveBeenCalledTimes(1);
383386
expect(completedListener).toHaveBeenLastCalledWith(
384387
expect.objectContaining({
385-
severity: 'error',
386-
toolsOutputMessages: expect.arrayContaining([
387-
'warning cbuild: missing ZEPHYR_BASE environment variable',
388-
'error cbuild: exec: "west": executable file not found in $PATH',
389-
]),
388+
severity: 'success',
389+
toolsOutputMessages: [], // Convert-only, no cbuild output
390390
}),
391391
);
392392

393+
// Verify cbuild setup was called asynchronously (fire-and-forget pattern)
394+
expect(mockRunCbuildSetup).toHaveBeenCalledTimes(1);
395+
393396
// Remove settings.json
394397
completedListener.mockClear();
395-
const settings = path.join(getWorkspaceFolder(), '.vscode', 'settings.json');
396398
mockRunCbuildSetup.mockClear();
399+
const settings = path.join(getWorkspaceFolder(), '.vscode', 'settings.json');
397400
fsUtils.deleteFileIfExists(settings);
398401
await fireAndWaitForConversion();
399402
expect(mockRunCbuildSetup).toHaveBeenCalledTimes(1);

src/solutions/solution-converter.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,6 @@ export class SolutionConverterImpl implements SolutionConverter {
173173

174174
let logResult = undefined;
175175
if (!detection) {
176-
if (convertResult.success) {
177-
// check if compile commands need to be updated: call cbuild setup skipping csolution convert step
178-
outputChannel.append('Setup database... ');
179-
let cbuildOutput = undefined;
180-
[convertResult.success, cbuildOutput] = await this.compileCommandsGenerator.runCbuildSetup();
181-
toolsOutputMessages = toolsOutputMessages.concat(cbuildOutput ?? []);
182-
}
183176
// rpc method: GetLogMessages
184177
outputChannel.append('Get log messages... ');
185178
logResult = await this.cmsisToolboxManager.runCsolutionRpc(
@@ -218,6 +211,14 @@ export class SolutionConverterImpl implements SolutionConverter {
218211
// apply select-compiler and discover layer configurations, reset state otherwise
219212
this.eventHub.fireConfigureSolutionDataReady({ availableCompilers, availableConfigurations });
220213

214+
// spawn cbuild setup asynchronously (fire-and-forget)
215+
// cbuild completion will be signaled via onDidCbuildCompleted event
216+
if (!detection && convertResult.success) {
217+
// check if compile commands need to be updated: call cbuild setup skipping csolution convert step
218+
outputChannel.append('Setup database... ');
219+
this.compileCommandsGenerator.runCbuildSetup(); // no await
220+
}
221+
221222
}
222223

223224
private async printErrorsWarnings(messages?: rpc.LogMessages): Promise<void> {

src/solutions/solution-event-hub.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export interface ConfigureSolutionData {
4040
/**
4141
* Base event data for cbuild setup completion result
4242
*/
43-
export interface CbuildCompletionData {
43+
export interface CbuildResultData {
4444
success: boolean;
4545
severity: Severity;
4646
toolsOutputMessages?: string[];
@@ -49,17 +49,11 @@ export interface CbuildCompletionData {
4949
/**
5050
* Event data for solution conversion result
5151
*/
52-
export interface ConvertResultData extends CbuildCompletionData {
52+
export interface ConvertResultData extends CbuildResultData {
5353
detection: boolean;
5454
logMessages: LogMessages;
5555
}
5656

57-
/**
58-
* Event data for cbuild setup completion result
59-
*/
60-
export interface CbuildResultData extends CbuildCompletionData {
61-
}
62-
6357
/**
6458
* Centralized event hub for managing and coordinating solution-related events.
6559
* Provides bidirectional asynchronous event processing with type-safe event registration and firing.

src/solutions/solution-problems.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { getFileNameFromPath } from '../utils/path-utils';
2424
import { stripTwoExtensions, stripVendor, stripVersion } from '../utils/string-utils';
2525
import { getWorkspaceFolder } from '../utils/vscode-utils';
2626
import { SolutionLoadStateChangeEvent, SolutionManager } from './solution-manager';
27-
import { ConvertResultData, SolutionEventHub } from './solution-event-hub';
27+
import { ConvertResultData, CbuildResultData, SolutionEventHub } from './solution-event-hub';
2828

2929
export const toolsPrefixPatterns = {
3030
error: /^.*error (?:cbuild|cbuild2cmake|csolution|cpackget):\s*/,
@@ -152,8 +152,15 @@ export class SolutionProblemsImpl implements SolutionProblems {
152152
await this.updateDiagnostics(data.logMessages);
153153
}
154154

155-
private async handleCbuildCompleted(): Promise<void> {
156-
// Cbuild completion handler (reserved for future use)
155+
private async handleCbuildCompleted(data: CbuildResultData): Promise<void> {
156+
// Enrich diagnostics with cbuild-specific output messages
157+
const logMessages: LogMessages = { success: true, errors: [], warnings: [], info: [] };
158+
await enrichLogMessagesFromToolOutput(logMessages, data.toolsOutputMessages);
159+
// Merge cbuild errors/warnings into existing diagnostics
160+
const csolution = this.solutionManager.getCsolution();
161+
if (csolution && (logMessages.errors?.length || logMessages.warnings?.length)) {
162+
await this.updateDiagnostics(logMessages);
163+
}
157164
}
158165

159166
private handleLoadStateChanged(data: SolutionLoadStateChangeEvent): void {

0 commit comments

Comments
 (0)