Skip to content

Commit

Permalink
Merge pull request #146 from Discookie/ericsson/not-analyzed
Browse files Browse the repository at this point in the history
Add support for CodeChecker warning/error reasons
  • Loading branch information
MiklosMagyari authored Jul 15, 2024
2 parents df64735 + e3c1391 commit 5374a75
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 70 deletions.
14 changes: 7 additions & 7 deletions src/backend/executor/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
parseShellArgsAndReplaceVariables,
replaceVariables
} from '../../utils/config';
import { ProcessStatus, ProcessType, ScheduledProcess } from '.';
import { ProcessStatusType, ProcessType, ScheduledProcess } from '.';
import { NotificationType } from '../../editor/notifications';
import { Editor } from '../../editor';

Expand Down Expand Up @@ -461,7 +461,7 @@ export class ExecutorBridge implements Disposable {
process.processStdout((output) => processOutput += output);

process.processStatusChange((status) => {
if (status === ProcessStatus.finished) {
if (status.type === ProcessStatusType.finished) {
ExtensionApi.metadata.parseCheckerData(processOutput);
}
});
Expand Down Expand Up @@ -504,7 +504,7 @@ export class ExecutorBridge implements Disposable {
process.processStdout((output) => processOutput += output);

process.processStatusChange((status) => {
if (status === ProcessStatus.finished) {
if (status.type === ProcessStatusType.finished) {
ExtensionApi.diagnostics.parseDiagnosticsData(processOutput);
}
});
Expand Down Expand Up @@ -558,9 +558,9 @@ export class ExecutorBridge implements Disposable {
process.processStdout((output) => processOutput += output);

process.processStatusChange(async (status) => {
switch (status) {
case ProcessStatus.running: return;
case ProcessStatus.finished:
switch (status.type) {
case ProcessStatusType.running: return;
case ProcessStatusType.finished:
try {
const data = JSON.parse(processOutput) as AnalyzerVersion;

Expand Down Expand Up @@ -651,7 +651,7 @@ export class ExecutorBridge implements Disposable {
}

break;
case ProcessStatus.removed:
case ProcessStatusType.removed:
if (this.checkedVersion === undefined) {
this.checkedVersion = false;
}
Expand Down
118 changes: 82 additions & 36 deletions src/backend/executor/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,24 @@ import * as os from 'os';
import { quote } from 'shell-quote';
import { Disposable, Event, EventEmitter, ExtensionContext, workspace } from 'vscode';

export enum ProcessStatus {
export enum ProcessStatusType {
notRunning,
running,
// When added to the execution queue
queued,
killed,
finished,
warning,
errored,
// When overwritten in the queue with 'replace', or cleared
removed,
}

export interface ProcessStatus {
type: ProcessStatusType,
reason?: string
}

export enum ProcessType {
analyze = 'CodeChecker analyze',
checkers = 'CodeChecker checkers',
Expand Down Expand Up @@ -57,6 +63,7 @@ export class ScheduledProcess implements Disposable {
public readonly commandArgs: string[];

private activeProcess?: childProcess.ChildProcess;
private lastLogMessage?: string;

/** Contains parameters for the executor. All members are defined. */
public readonly processParameters: ProcessParameters;
Expand Down Expand Up @@ -85,8 +92,8 @@ export class ScheduledProcess implements Disposable {
return this._processStderr.event;
}

private _processStatus: ProcessStatus = ProcessStatus.notRunning;
public get processStatus(): ProcessStatus {
private _processStatus: ProcessStatusType = ProcessStatusType.notRunning;
public get processStatus(): ProcessStatusType {
return this._processStatus;
}

Expand All @@ -106,14 +113,27 @@ export class ScheduledProcess implements Disposable {
if (this.processParameters.forwardStdoutToLogs === undefined) {
this.processParameters.forwardStdoutToLogs = !forwardDefaults.includes(processType);
}

const parseLogMessage = (stdout: string) => {
// Do not store json output or meta messages as last error
const lines = stdout.split('\n')
.filter((line) => !line.startsWith('{') && !line.startsWith('>') && line !== '');

if (lines.length > 0) {
this.lastLogMessage = lines[lines.length - 1];
}
};

this.processStdout(parseLogMessage, this);
this.processStderr(parseLogMessage, this);
}

dispose() {
if (this.activeProcess) {
this.killProcess();
}

this._processStatusChange.fire(ProcessStatus.removed);
this._processStatusChange.fire({ type: ProcessStatusType.removed });

this._processStatusChange.dispose();
this._processStdout.dispose();
Expand Down Expand Up @@ -153,7 +173,7 @@ export class ScheduledProcess implements Disposable {

this.activeProcess.on('error', (err) => {
this._processStderr.fire(`>>> Process '${commonName}' errored: ${err.message}\n`);
this.updateStatus(ProcessStatus.errored);
this.updateStatus(ProcessStatusType.errored);
});
// Guaranteed to fire after all datastreams are closed
this.activeProcess.on('close', (code: number | null) => {
Expand All @@ -163,15 +183,15 @@ export class ScheduledProcess implements Disposable {
case null:
case 0:
case 2:
this.updateStatus(ProcessStatus.finished);
this.updateStatus(ProcessStatusType.finished);
break;
default:
this.updateStatus(ProcessStatus.errored);
this.updateStatus(ProcessStatusType.errored);
break;
}
});

this.updateStatus(ProcessStatus.running);
this.updateStatus(ProcessStatusType.running);
}

public killProcess() {
Expand All @@ -182,28 +202,54 @@ export class ScheduledProcess implements Disposable {
this.activeProcess.kill('SIGINT');
this._processStderr.fire('>>> Process killed\n');

this.updateStatus(ProcessStatus.killed);
this.updateStatus(ProcessStatusType.killed);
}

private updateStatus(status: ProcessStatus) {
switch (status) {
case ProcessStatus.running:
if (this._processStatus !== ProcessStatus.running) {
this._processStatus = ProcessStatus.running;
this._processStatusChange.fire(ProcessStatus.running);
private updateStatus(type: ProcessStatusType) {
switch (type) {
case ProcessStatusType.running:
if (this._processStatus !== ProcessStatusType.running) {
this._processStatus = ProcessStatusType.running;
this._processStatusChange.fire({ type: ProcessStatusType.running });
}
break;
case ProcessStatus.removed:
return;
case ProcessStatusType.removed:
// dispose() calls killProcess before dispatching this event.
this._processStatusChange.fire(ProcessStatus.removed);
break;
default:
if (this._processStatus === ProcessStatus.running) {
this.activeProcess = undefined;
this._processStatus = ProcessStatus.notRunning;
this._processStatusChange.fire(status);
this._processStatusChange.fire({ type: ProcessStatusType.removed });
return;
}

if (this._processStatus === ProcessStatusType.running) {
this.activeProcess = undefined;
this._processStatus = ProcessStatusType.notRunning;

const lastLogMessage = this.lastLogMessage?.replace(/^\[.+\]/, '');
const lastLogSeverity = this.lastLogMessage?.match(/^\[(\w+)/)?.[1];

if (type === ProcessStatusType.errored) {
this._processStatusChange.fire({ type, reason: lastLogMessage });
return;
} else if (type !== ProcessStatusType.finished) {
this._processStatusChange.fire({ type });
return;
}

// Refine the finished process status based on the last log message
switch (lastLogSeverity) {
case 'CRITICAL':
case 'ERROR':
this._processStatusChange.fire({ type: ProcessStatusType.errored, reason: lastLogMessage });
break;
case 'WARNING':
this._processStatusChange.fire({ type: ProcessStatusType.warning, reason: lastLogMessage });
break;
case 'DEBUG':
this._processStatusChange.fire({ type: ProcessStatusType.finished });
break;
default:
this._processStatusChange.fire({ type: ProcessStatusType.finished, reason: lastLogMessage });
break;
}
break;
}
}
}
Expand Down Expand Up @@ -253,8 +299,8 @@ export class ExecutorManager implements Disposable {
return this._processStderr.event;
}

private _processStatus: ProcessStatus = ProcessStatus.notRunning;
public get processStatus(): ProcessStatus {
private _processStatus: ProcessStatusType = ProcessStatusType.notRunning;
public get processStatus(): ProcessStatusType {
return this._processStatus;
}

Expand All @@ -273,12 +319,12 @@ export class ExecutorManager implements Disposable {
}

private updateStatus([status, process]: [ProcessStatus, ScheduledProcess]) {
switch (status) {
case ProcessStatus.removed:
switch (status.type) {
case ProcessStatusType.removed:
this._processStatusChange.fire([status, process]);
break;
case ProcessStatus.running:
case ProcessStatus.queued:
case ProcessStatusType.running:
case ProcessStatusType.queued:
this._processStatusChange.fire([status, process]);
break;
default:
Expand Down Expand Up @@ -330,7 +376,7 @@ export class ExecutorManager implements Disposable {
switch (method) {
case 'replace':
for (const entry of namedQueue) {
this.updateStatus([ProcessStatus.removed, entry]);
this.updateStatus([{ type: ProcessStatusType.removed }, entry]);
entry.dispose();
}

Expand All @@ -345,7 +391,7 @@ export class ExecutorManager implements Disposable {
break;
}

this.updateStatus([ProcessStatus.queued, process]);
this.updateStatus([{ type: ProcessStatusType.queued }, process]);
this.queue.set(name, namedQueue);

this.startNextProcess();
Expand All @@ -359,7 +405,7 @@ export class ExecutorManager implements Disposable {
if (namedQueue.some((queueItem) => queueItem.commandLine === process.commandLine)) {
if (!silent) {
for (const entry of namedQueue.filter((queueItem) => queueItem.commandLine === process.commandLine)) {
this.updateStatus([ProcessStatus.removed, entry]);
this.updateStatus([{ type: ProcessStatusType.removed }, entry]);
entry.dispose();
}
}
Expand All @@ -375,15 +421,15 @@ export class ExecutorManager implements Disposable {
public clearQueue(name?: string) {
if (name) {
for (const entry of this.queue.get(name) ?? []) {
this.updateStatus([ProcessStatus.removed, entry]);
this.updateStatus([{ type: ProcessStatusType.removed }, entry]);
entry.dispose();
}

this.queue.set(name, []);
} else {
for (const [, queue] of this.queue.entries()) {
for (const entry of queue) {
this.updateStatus([ProcessStatus.removed, entry]);
this.updateStatus([{ type: ProcessStatusType.removed }, entry]);
entry.dispose();
}
}
Expand Down
18 changes: 10 additions & 8 deletions src/editor/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from 'vscode';
import { Editor } from '.';
import { ExtensionApi } from '../backend';
import { ProcessStatus, ScheduledProcess } from '../backend/executor/process';
import { ProcessStatus, ProcessStatusType, ScheduledProcess } from '../backend/executor/process';
import { getConfigAndReplaceVariables } from '../utils/config';
import { NotificationType } from './notifications';

Expand Down Expand Up @@ -93,28 +93,30 @@ export class ExecutorAlerts {
return;
}

if (status === ProcessStatus.running) {
if (status.type === ProcessStatusType.running) {
this.statusBarItem.text = '$(loading) CodeChecker: analysis in progress...';
this.statusBarItem.show();
return;
}

switch (status) {
case ProcessStatus.finished:
switch (status.type) {
case ProcessStatusType.finished:
this.statusBarItem.text = '$(testing-passed-icon) CodeChecker: analysis finished';
break;
case ProcessStatus.killed:
case ProcessStatusType.killed:
this.statusBarItem.text = '$(testing-failed-icon) CodeChecker: analysis killed';
break;
case ProcessStatus.notRunning:
case ProcessStatusType.notRunning:
this.statusBarItem.text = '$(info) CodeChecker: ready';
break;
case ProcessStatus.errored:
case ProcessStatusType.errored:
this.statusBarItem.text = '$(testing-error-icon) CodeChecker: analysis errored';

const logLocation = status.reason ? 'sidebar' : 'output log';

Editor.notificationHandler.showNotification(
NotificationType.error,
'CodeChecker finished with error - see logs for details'
`CodeChecker finished with error - see the ${logLocation} for details`
);
break;
default:
Expand Down
Loading

0 comments on commit 5374a75

Please sign in to comment.