From 776ca03dc5c9acb8289c8922e8bbfd558be828bb Mon Sep 17 00:00:00 2001 From: Anatoli Ivanov Date: Thu, 10 Mar 2022 11:24:10 +0300 Subject: [PATCH 1/3] Make linter tolerant to '--showfile' option This forces '--showfile' mode to make linter stable whether the option passed directly by the arg or implicitly by .config file --- src/checkpatchProvider.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/checkpatchProvider.ts b/src/checkpatchProvider.ts index 37f703e..b86f2f8 100644 --- a/src/checkpatchProvider.ts +++ b/src/checkpatchProvider.ts @@ -102,14 +102,14 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { private parseCheckpatchLog(log: string, basePath: string): number { const dictionary: { [fileUri: string]: vscode.Diagnostic[] } = {}; - var re = /(WARNING|ERROR|CHECK): ?(.+):(.+)?(?:\n|\r\n|)#\d+: FILE: (.*):(\d+):/g; + var re = /(.*):(\d+): (WARNING|ERROR|CHECK): ?(.+):(.+)/g; var matches; while (matches = re.exec(log)) { - let type = matches[2]; - let message = matches[3]; - let fileName = matches[4]; - let errorline = parseInt(matches[5]); + let fileName = matches[1]; + let errorline = parseInt(matches[2]); + let type = matches[4]; + let message = matches[5]; let range = new vscode.Range(errorline - 1, 0, errorline - 1, Number.MAX_VALUE); let diagnostic = new vscode.Diagnostic(range, `${type}:${message}`, this.linterConfig.diagnosticSeverity); @@ -143,7 +143,9 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { let log = ''; let args = this.linterConfig.args.slice(); let cwd = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : undefined; - args.push('--show-types -f'); + args.push('--show-types'); + args.push('--showfile'); + args.push('-f'); args.push(textDocument.fileName.replace(/\\/g, '/')); let childProcess = cp.spawn(this.linterConfig.path, args, { shell: true, cwd: cwd }); @@ -195,6 +197,7 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { if (commitValue && commitValue.description) { let log = ''; let args = this.linterConfig.args.slice(); + args.push('--showfile'); args.push('-g'); args.push(commitValue.description); From fa14fb0da5a9115396dab642a3c71d2acab2cce3 Mon Sep 17 00:00:00 2001 From: Anatoli Ivanov Date: Thu, 10 Mar 2022 11:24:28 +0300 Subject: [PATCH 2/3] checkpatchCommit(): fix log format violation By design linter is run from the directory where the repo containing commit is located. And in case when there is no '--show-types' option passed the resulting log violates expected format and parseCheckpatchLog() doesn't see what it should. Forcing the option fixes the problem. --- src/checkpatchProvider.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/checkpatchProvider.ts b/src/checkpatchProvider.ts index b86f2f8..a37ee3a 100644 --- a/src/checkpatchProvider.ts +++ b/src/checkpatchProvider.ts @@ -197,6 +197,7 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { if (commitValue && commitValue.description) { let log = ''; let args = this.linterConfig.args.slice(); + args.push('--show-types'); args.push('--showfile'); args.push('-g'); args.push(commitValue.description); From 86d2b1be7a5a34f6057dbd7473e2657114481cf6 Mon Sep 17 00:00:00 2001 From: Anatoli Ivanov Date: Tue, 15 Mar 2022 22:17:56 +0300 Subject: [PATCH 3/3] Advance multiroot workspace support a) This adds an ability to have a workspace-folder-specific checkpatch config. This useful in case when you have projects with different requirements in your multiroot workspace. b) This adds a checkpatch-specific output channel (output pane of vscode) c) This adds 'Clean Current Diagnostic' command to clean up problems pane manually --- README.md | 1 + package.json | 35 +++- src/checkpatchProvider.ts | 380 ++++++++++++++++++++++++++++++++------ 3 files changed, 355 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index b5ce4f1..9244ece 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ GNU 'diff' executable should also be available (can be done by installing [git-f ## Settings * `checkpatch.checkpatchPath` Path to the checkpatch.pl script * `checkpatch.checkpatchArgs` checkpatch arguments to use +* `checkpatch.useFolderAsCwd` Relative to multiroot workspace layout. Whether the linter should run in the workspace where the file is from or use the root workspace * `checkpatch.run` Control whether the linting is automatic on save or manually triggered using the `checkpatch.checkFile` command. * `checkpatch.exclude` Glob patterns for excluding files and folders from automatic checks. * `checkpatch.diagnosticLevel` Diagnostic level of checkpatch errors. diff --git a/package.json b/package.json index 89faabd..3890b58 100644 --- a/package.json +++ b/package.json @@ -35,14 +35,16 @@ "checkpatch.checkpatchPath": { "type": "string", "default": "checkpatch.pl", - "description": "Path to the checkpatch.pl script" + "description": "Path to the checkpatch.pl script. Should be set at least for the root workspace", + "scope": "resource" }, "checkpatch.checkpatchArgs": { "type": "array", "default": [ "--no-tree" ], - "description": "Arguments for the checkpatch script" + "description": "Arguments for the checkpatch script", + "scope": "resource" }, "checkpatch.run": { "type": "string", @@ -51,12 +53,13 @@ "manual" ], "default": "onSave", - "description": "Whether the linter is run automatically on save or manually." + "description": "Whether the linter is run automatically on save or manually" }, "checkpatch.exclude": { "type": "array", "default": [], - "description": "Glob patterns for excluding files and folders from automatic checks." + "description": "Glob patterns for excluding files and folders from automatic checks", + "scope": "resource" }, "checkpatch.diagnosticLevel": { "type": "string", @@ -68,21 +71,31 @@ ], "default": "Information", "description": "Select the diagnostic level of checkpatch problems" + }, + "checkpatch.useFolderAsCwd": { + "type": "boolean", + "default": false, + "description": "Whether the linter should use current folder as cwd or run from root folder instead. Only applies when there `#checkpatch.checkpatchPath#` is not set for current folder", + "scope": "resource" } } }, "commands": [ { "command": "checkpatch.checkFile", - "title": "Checkpatch Selected File" + "title": "Checkpatch: Check Selected File" }, { "command": "checkpatch.checkCommit", - "title": "Checkpatch Commit" + "title": "Checkpatch: Check Commit" }, { "command": "checkpatch.toggleAutoRun", - "title": "Toggle Checkpatch for the Current Workspace" + "title": "Checkpatch: Toggle Run Mode For The Current Workspace" + }, + { + "command": "checkpatch.cleanDiagnostic", + "title": "Checkpatch: Clean Current Diagnostic" } ], "problemMatchers": [ @@ -103,6 +116,13 @@ "regexp": "#\\d+: FILE: (.*):(\\d+):", "file": 1, "line": 2 + }, + { + "regexp": "(.*):(\\d+): (WARNING|ERROR|CHECK): ?(.+):(.+)", + "file": 1, + "line": 2, + "severity": 3, + "message": 5 } ] } @@ -136,6 +156,7 @@ "@types/vscode": "^1.34.0", "@typescript-eslint/eslint-plugin": "^3.0.2", "@typescript-eslint/parser": "^3.0.2", + "esbuild": "^0.14.25", "eslint": "^7.1.0", "typescript": "^4.0.2" }, diff --git a/src/checkpatchProvider.ts b/src/checkpatchProvider.ts index a37ee3a..797e1ba 100644 --- a/src/checkpatchProvider.ts +++ b/src/checkpatchProvider.ts @@ -5,13 +5,21 @@ import * as vscode from 'vscode'; import * as minimatch from 'minimatch'; import { GitExtension, API as GitAPI, Repository, } from './typings/git'; -export interface LinterConfig { +export interface CommonLinterConfig { path: string; args: string[]; excludeGlobs: string[]; + useAsCwd: boolean; diagnosticSeverity: vscode.DiagnosticSeverity; } +export interface FolderLinterConfig { + path: string | undefined; + args: string[] | undefined; + excludeGlobs: string[] | undefined; + useAsCwd: boolean | undefined; +} + interface RepoPickItem extends vscode.QuickPickItem { repo: Repository; } @@ -24,12 +32,44 @@ const diagSeverityMap = new Map([ ]); export default class CheckpatchProvider implements vscode.CodeActionProvider { - private linterConfig!: LinterConfig; + private isConfigured: boolean = false; + private commonLinterConfig!: CommonLinterConfig; + private folderLinterConfigs: { [folderPath: string]: FolderLinterConfig } = {}; private documentListener!: vscode.Disposable; private diagnosticCollection = vscode.languages.createDiagnosticCollection('checkpatch'); private git!: GitAPI; + private outputChannel: vscode.OutputChannel | undefined; + + private log(value: string): void { + this.outputChannel?.appendLine(value); + } + + private prettify(value: string | string[] | undefined): string | undefined { + let result = undefined; + + if (value) { + if (!Array.isArray(value)) { + result = '"' + value + '"'; + } else { + result = '['; + for (let s of value) { + if (result != '[') { + result += ', '; + } + result += this.prettify(s); + } + result += ']'; + } + } + + return result; + } public activate(subscriptions: vscode.Disposable[]) { + if (!this.outputChannel) { + this.outputChannel = vscode.window.createOutputChannel('Checkpatch'); + } + subscriptions.push(this); vscode.workspace.onDidCloseTextDocument((textDocument) => { // FIXME: this is the wrong event, happening only when removed from cache @@ -57,42 +97,143 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { (config.run === 'onSave') ? 'manual' : 'onSave', vscode.ConfigurationTarget.Workspace); }); + + vscode.commands.registerCommand('checkpatch.cleanDiagnostic', () => this.diagnosticCollection.clear()); } - private loadConfig(): void { - const config = vscode.workspace.getConfiguration('checkpatch'); + private maybeConfigure(): string { + if (!this.isConfigured) { + this.loadConfig(); + } - this.linterConfig = { - path: config.checkpatchPath, - args: config.checkpatchArgs, - excludeGlobs: config.exclude, - diagnosticSeverity: diagSeverityMap.get(config.diagnosticLevel) ?? vscode.DiagnosticSeverity.Information - }; + if (!this.isConfigured) { + return 'fail'; + } + + return 'ok'; + } + + private testConfig(description: string, linterPath: string, args: string[], cwd: string | undefined): string { + this.log(`Test ${description}`); + + var re = /total: \d* errors, \d* warnings,( \d* checks,)? \d* lines checked/g; + + args.push('--no-tree - '); + + let childProcess = cp.spawnSync(linterPath, args, {shell: true, input: ' ', cwd: cwd}); + if (childProcess.pid && childProcess.stdout && re.test(childProcess.stdout.toString())) { + return 'ok'; + } + + this.log( + `Test ${description}: probably bad or unusable config. Failed to call "${linterPath}" to test for it works` + + `${childProcess.stderr ? '. Stderr: "' + childProcess.stderr.toString().trim() + '"' : ''}` + ); + vscode.window.showErrorMessage(`Checkpatch [config]: Probably bad or unusable config. Please, review the output pane for details`); + + return 'fail'; + } + + private loadConfig(): void { + this.isConfigured = false; if (this.documentListener) { this.documentListener.dispose(); } this.diagnosticCollection.clear(); - // testing given configuration: - var re = /total: \d* errors, \d* warnings,( \d* checks,)? \d* lines checked/g; - let args = this.linterConfig.args.slice(); - let cwd = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : undefined; - args.push('--no-tree - '); - let childProcess = cp.spawnSync(this.linterConfig.path, args, {shell: true, input: ' ', cwd: cwd }); - if (childProcess.pid && childProcess.stdout && re.test(childProcess.stdout.toString())) { - // all good - } else { - vscode.window.showErrorMessage( - `Checkpatch: calling '${this.linterConfig.path}' failed, please check checkpatch.checkpatchPath and checkpatch.checkpatchPath configutations.`); - if (childProcess.stderr) - console.log(`Checkpatch: '${childProcess.stderr.toString()}'`) + const commonConfig = vscode.workspace.getConfiguration('checkpatch'); + + this.commonLinterConfig = { + path: commonConfig.checkpatchPath, + args: commonConfig.checkpatchArgs, + excludeGlobs: commonConfig.exclude, + useAsCwd: commonConfig.useFolderAsCwd, + diagnosticSeverity: diagSeverityMap.get(commonConfig.diagnosticLevel) ?? vscode.DiagnosticSeverity.Information + }; + + let relativePathMessage = ''; + + // make path absolute if needed and possible. Relative form may impact when cwd is changed + if (!path.isAbsolute(this.commonLinterConfig.path) && vscode.workspace.workspaceFolders) { + this.commonLinterConfig.path = path.join(vscode.workspace.workspaceFolders[0].uri.fsPath, this.commonLinterConfig.path); + relativePathMessage = ' (converted to absolute using root folder path)'; + } + + this.log( + `Load common config:\n` + + ` - checkpatchPath: ${this.prettify(this.commonLinterConfig.path) + relativePathMessage}\n` + + ` - checkpatchArgs: ${this.prettify(this.commonLinterConfig.args)}\n` + + ` - exclude: ${this.prettify(this.commonLinterConfig.excludeGlobs)}\n` + + ` - useFolderAsCwd: ${this.commonLinterConfig.useAsCwd}\n` + + ` - diagnosticLevel: ${commonConfig.diagnosticLevel}` + ); + + // get folder config(-s) + this.folderLinterConfigs = {}; + if (vscode.workspace.workspaceFolders) { + for (let folder of vscode.workspace.workspaceFolders) { + const folderConfig = vscode.workspace.getConfiguration('checkpatch', folder); + const pathInspection = folderConfig.inspect('checkpatchPath'); + const argsInspection = folderConfig.inspect('checkpatchArgs'); + const excludeInspection = folderConfig.inspect('exclude'); + const cwdInspection = folderConfig.inspect('useFolderAsCwd'); + + let folderLinterConfig: FolderLinterConfig = { + path: pathInspection?.workspaceFolderValue, + args: argsInspection?.workspaceFolderValue, + excludeGlobs: excludeInspection?.workspaceFolderValue, + useAsCwd: cwdInspection?.workspaceFolderValue + }; + + if (folderLinterConfig.path && !path.isAbsolute(folderLinterConfig.path)) { + folderLinterConfig.path = path.join(folder.uri.fsPath, folderLinterConfig.path); + relativePathMessage = ' (converted to absolute)'; + } else { + relativePathMessage = ''; + } + + this.log( + `Load folder config @ "${folder.uri.fsPath}":\n` + + ` - checkpatchPath: ${this.prettify(folderLinterConfig.path) + relativePathMessage}\n` + + ` - checkpatchArgs: ${this.prettify(folderLinterConfig.args)}\n` + + ` - exclude: ${this.prettify(folderLinterConfig.excludeGlobs)}\n` + + ` - useFolderAsCwd: ${folderLinterConfig.useAsCwd}` + ); + + this.folderLinterConfigs[folder.uri.fsPath] = folderLinterConfig; + } + } + + // test config(-s) + if ('ok' != this.testConfig( + `common config`, + this.commonLinterConfig.path, + this.commonLinterConfig.args.slice(), + vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : undefined + )) { + this.log(`Not configured!`); return; } + for (const [folderPath, folderLinterConfig] of Object.entries(this.folderLinterConfigs)) { + if ('ok' != this.testConfig( + `folder config @ "${folderPath}"`, + folderLinterConfig.path ?? this.commonLinterConfig.path, + (folderLinterConfig.args ?? this.commonLinterConfig.args).slice(), + (folderLinterConfig.path || folderLinterConfig.useAsCwd || this.commonLinterConfig.useAsCwd) ? folderPath : vscode.workspace.workspaceFolders?.[0].uri.fsPath + )) { + this.log(`Not configured!`); + return; + } + } - if (config.run === 'onSave') { + if (commonConfig.run === 'onSave') { this.documentListener = vscode.workspace.onDidSaveTextDocument(this.checkpatchFile, this); } + + this.log(`Configured`); + + this.isConfigured = true; } public dispose(): void { @@ -104,6 +245,7 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { const dictionary: { [fileUri: string]: vscode.Diagnostic[] } = {}; var re = /(.*):(\d+): (WARNING|ERROR|CHECK): ?(.+):(.+)/g; var matches; + let numError = 0; while (matches = re.exec(log)) { let fileName = matches[1]; @@ -111,7 +253,7 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { let type = matches[4]; let message = matches[5]; let range = new vscode.Range(errorline - 1, 0, errorline - 1, Number.MAX_VALUE); - let diagnostic = new vscode.Diagnostic(range, `${type}:${message}`, this.linterConfig.diagnosticSeverity); + let diagnostic = new vscode.Diagnostic(range, `${type}:${message}`, this.commonLinterConfig.diagnosticSeverity); diagnostic.code = type; diagnostic.source = 'checkpatch'; @@ -126,45 +268,121 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { this.diagnosticCollection.set(vscode.Uri.file(path.join(basePath, uri)), dictionary[uri]); } - return Object.keys(dictionary).length; + for (const [fileUri, errors] of Object.entries(dictionary)) { + numError += Object.keys(errors).length + } + + return numError; } - private checkpatchFile( - textDocument: vscode.TextDocument): any { + private checkpatchFile(textDocument: vscode.TextDocument): any { if (textDocument.languageId !== 'c') { return; } - for (var excludeGlob of this.linterConfig.excludeGlobs) { + + if (this.maybeConfigure() != 'ok') { + this.log(`Check file: bad config yet`); + return; + } + + let workspaceFolderPath = undefined; + + if (vscode.workspace.workspaceFolders) { + for (let folder of vscode.workspace.workspaceFolders) { + // Here we search for the most long path overlap. + // For cases when subfolders are included to workspace as workspace folders. + if (textDocument.fileName.startsWith(folder.uri.fsPath) + && (!workspaceFolderPath || folder.uri.fsPath.length > workspaceFolderPath.length)) { + workspaceFolderPath = folder.uri.fsPath; + } + } + } + + let linterPath: [any, string] = [undefined, '']; + let linterArgs: [any, string] = [undefined, '']; + let excludeGlobs: [any, string] = [undefined, '']; + let useAsCwd: [any, string] = [undefined, '']; + let linterCwd: [any, string] = [undefined, '']; + + if (workspaceFolderPath) { + if (workspaceFolderPath in this.folderLinterConfigs) { + linterPath[0] = this.folderLinterConfigs[workspaceFolderPath].path; + linterArgs[0] = this.folderLinterConfigs[workspaceFolderPath].args; + excludeGlobs[0] = this.folderLinterConfigs[workspaceFolderPath].excludeGlobs; + useAsCwd[0] = this.folderLinterConfigs[workspaceFolderPath].useAsCwd; + } else { + this.log(`Check file "${textDocument.fileName}": folder config is not defined!`); + } + } + + if (useAsCwd[0] === undefined) { + useAsCwd = [this.commonLinterConfig.useAsCwd, ' (from common config)']; + } + + linterCwd = workspaceFolderPath && (linterPath[0] || useAsCwd[0]) + ? [workspaceFolderPath, ''] + : [vscode.workspace.workspaceFolders?.[0].uri.fsPath, ' (root folder used as cwd)']; + + if (linterPath[0] === undefined) { + linterPath = [this.commonLinterConfig.path, ' (from common config)']; + } + if (linterArgs[0] === undefined) { + linterArgs = [this.commonLinterConfig.args, ' (from common config)']; + } + if (excludeGlobs[0] === undefined) { + excludeGlobs = [this.commonLinterConfig.excludeGlobs, ' (from common config)']; + } + + this.log( + `Check file "${textDocument.fileName}":\n` + + ` - workspace folder: ${this.prettify(workspaceFolderPath)}\n` + + ` - checkpatchPath: ${this.prettify(linterPath[0]) + linterPath[1]}\n` + + ` - checkpatchArgs: ${this.prettify(linterArgs[0]) + linterArgs[1]}\n` + + ` - exclude: ${this.prettify(excludeGlobs[0]) + excludeGlobs[1]}\n` + + ` - useFolderAsCwd: ${useAsCwd[0] + useAsCwd[1]}\n` + + ` - cwd: ${this.prettify(linterCwd[0]) + linterCwd[1]}` + ); + + for (var excludeGlob of excludeGlobs[0]) { if (minimatch(textDocument.fileName, excludeGlob)) { return; } } + linterArgs[0] = linterArgs[0].slice(); + linterArgs[0].push('--show-types'); + linterArgs[0].push('--showfile'); + linterArgs[0].push('-f'); + linterArgs[0].push(textDocument.fileName.replace(/\\/g, '/')); + let log = ''; - let args = this.linterConfig.args.slice(); - let cwd = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : undefined; - args.push('--show-types'); - args.push('--showfile'); - args.push('-f'); - args.push(textDocument.fileName.replace(/\\/g, '/')); - - let childProcess = cp.spawn(this.linterConfig.path, args, { shell: true, cwd: cwd }); + let childProcess = cp.spawn(linterPath[0], linterArgs[0], { shell: true, cwd: linterCwd[0] }); if (childProcess.pid) { // clean old diagostics. Prevents files with only one warning from being updated this.diagnosticCollection.delete(textDocument.uri); childProcess.stdout.on('data', (data: Buffer) => log += data); - childProcess.stdout.on('end', () => this.parseCheckpatchLog(log, '')); + childProcess.stdout.on('end', () => { + let numError = this.parseCheckpatchLog(log, '') + this.log(`Check file "${textDocument.fileName}": done, ${numError} errors found`); + }); } else { - vscode.window.showErrorMessage( - `Checkpatch: calling '${this.linterConfig.path}' failed, please check checkpatch is available and change config.checkpatchPath accordingly`); - return; + this.log( + `Check file "${textDocument.fileName}": failed to call "${linterPath[0]}"\ + ${childProcess.stderr ? '. Stderr: "' + childProcess.stderr.toString().trim() + '"' : ''}` + ); + vscode.window.showErrorMessage(`Checkpatch [file]: Check failed. Please, review the output pane for details`); } } private async checkpatchCommit(): Promise { + if (this.maybeConfigure() != 'ok') { + this.log(`Check commit: bad config yet`); + return; + } + let repo: Repository; if (this.git.repositories.length === 0) { - vscode.window.showErrorMessage(`Checkpatch: No repositories in workspace`); + vscode.window.showErrorMessage(`Checkpatch [commit]: No repositories in workspace`); return; } if (this.git.repositories.length === 1) { @@ -195,14 +413,64 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { const commitValue = await vscode.window.showQuickPick(commitsItems, { placeHolder: 'Select commit' }); if (commitValue && commitValue.description) { - let log = ''; - let args = this.linterConfig.args.slice(); - args.push('--show-types'); - args.push('--showfile'); - args.push('-g'); - args.push(commitValue.description); + let workspaceFolderPath = undefined; + + if (vscode.workspace.workspaceFolders) { + for (let folder of vscode.workspace.workspaceFolders) { + if (repo.rootUri.path == folder.uri.fsPath) { + workspaceFolderPath = repo.rootUri.path; + break; + } + } + } + + let linterPath: [any, string] = [undefined, '']; + let linterArgs: [any, string] = [undefined, '']; + let useAsCwd: [any, string] = [undefined, '']; + let linterCwd: [any, string] = [undefined, '']; - let childProcess = cp.spawn(this.linterConfig.path, args, { shell: true, cwd: repo.rootUri.fsPath }); + if (workspaceFolderPath) { + if (workspaceFolderPath in this.folderLinterConfigs) { + linterPath[0] = this.folderLinterConfigs[workspaceFolderPath].path; + linterArgs[0] = this.folderLinterConfigs[workspaceFolderPath].args; + useAsCwd[0] = this.folderLinterConfigs[workspaceFolderPath].useAsCwd; + } else { + this.log(`Check commit ${commitValue.description} @ "${repo.rootUri.path}": folder config is not defined!`); + } + } + + if (useAsCwd[0] === undefined) { + useAsCwd = [this.commonLinterConfig.useAsCwd, ' (from common config)']; + } + + linterCwd = workspaceFolderPath && (linterPath[0] || useAsCwd[0]) + ? [workspaceFolderPath, ''] + : [vscode.workspace.workspaceFolders?.[0].uri.fsPath, ' (root folder used as cwd)']; + + if (linterPath[0] === undefined) { + linterPath = [this.commonLinterConfig.path, ' (from common config)']; + } + if (linterArgs[0] === undefined) { + linterArgs = [this.commonLinterConfig.args, ' (from common config)']; + } + + this.log( + `Check commit ${commitValue.description} @ "${repo.rootUri.path}":\n` + + ` - workspace folder: ${this.prettify(workspaceFolderPath)}\n` + + ` - checkpatchPath: ${this.prettify(linterPath[0]) + linterPath[1]}\n` + + ` - checkpatchArgs: ${this.prettify(linterArgs[0]) + linterArgs[1]}\n` + + ` - useFolderAsCwd: ${useAsCwd[0] + useAsCwd[1]}\n` + + ` - cwd: ${this.prettify(linterCwd[0]) + linterCwd[1]}` + ); + + linterArgs[0] = linterArgs[0].slice(); + linterArgs[0].push('--show-types'); + linterArgs[0].push('--showfile'); + linterArgs[0].push('-g'); + linterArgs[0].push(commitValue.description); + + let log = ''; + let childProcess = cp.spawn(linterPath[0], linterArgs[0], { shell: true, cwd: linterCwd[0] }); if (childProcess.pid) { childProcess.stdout.on('data', (data: Buffer) => log += data); childProcess.stdout.on('end', () => { @@ -210,16 +478,20 @@ export default class CheckpatchProvider implements vscode.CodeActionProvider { this.diagnosticCollection.clear(); const numError = this.parseCheckpatchLog(log, repo.rootUri.fsPath); if (numError > 0) { - vscode.window.showErrorMessage(`Checkpatch: commit has style problems, please review the problems pane`); + vscode.window.showErrorMessage(`Checkpatch [commit]: Commit has style problems, please review the problems pane`); vscode.commands.executeCommand('workbench.actions.view.problems'); } else { - vscode.window.showInformationMessage(`Checkpatch: commit has no obvious style problems and is ready for submission.`); + vscode.window.showInformationMessage(`Checkpatch [commit]: Commit has no obvious style problems and is ready for submission`); } + + this.log(`Check commit ${commitValue.description} @ "${repo.rootUri.path}": done, ${numError} errors found`); }); } else { - vscode.window.showErrorMessage( - `Checkpatch: calling '${this.linterConfig.path}' failed, please check checkpatch is available and change config.checkpatchPath accordingly`); - return; + this.log( + `Check commit ${commitValue.description} @ "${repo.rootUri.path}": failed to call "${linterPath[0]}"\ + ${childProcess.stderr ? '. Stderr: "' + childProcess.stderr.toString().trim() + '"' : ''}` + ); + vscode.window.showErrorMessage(`Checkpatch [commit]: Check failed. Please, review the output pane for details`); } } }