diff --git a/src/goCheck.ts b/src/goCheck.ts index 933fb13c1..0053d4d3b 100644 --- a/src/goCheck.ts +++ b/src/goCheck.ts @@ -23,7 +23,18 @@ export interface ICheckResult { severity: string; } -function runTool(cmd: string, args: string[], cwd: string, severity: string, useStdErr: boolean, toolName: string, notFoundError?: string) { +/** + * Runs given Go tool and returns errors/warnings that can be fed to the Problems Matcher + * @param args Arguments to be passed while running given tool + * @param cwd cwd that will passed in the env object while running given tool + * @param serverity error or warning + * @param useStdErr If true, the stderr of the output of the given tool will be used, else stdout will be used + * @param toolName The name of the Go tool to run. If none is provided, the go runtime itself is used + * @param printUnexpectedOutput If true, then output that doesnt match expected format is printed to the output channel + */ +function runTool(args: string[], cwd: string, severity: string, useStdErr: boolean, toolName: string, printUnexpectedOutput?: boolean): Promise { + let goRuntimePath = getGoRuntimePath(); + let cmd = toolName ? getBinPath(toolName) : goRuntimePath; return new Promise((resolve, reject) => { cp.execFile(cmd, args, { cwd: cwd }, (err, stdout, stderr) => { try { @@ -31,10 +42,15 @@ function runTool(cmd: string, args: string[], cwd: string, severity: string, use if (toolName) { promptForMissingTool(toolName); } else { - vscode.window.showInformationMessage(notFoundError); + vscode.window.showInformationMessage(`Cannot find ${goRuntimePath}`); } return resolve([]); } + if (err && stderr && !useStdErr) { + outputChannel.appendLine(['Error while running tool:', cmd, ...args].join(' ')); + outputChannel.appendLine(stderr); + return resolve([]); + } let lines = (useStdErr ? stderr : stdout).toString().split('\n'); outputChannel.appendLine(['Finished running tool:', cmd, ...args].join(' ')); @@ -45,7 +61,10 @@ function runTool(cmd: string, args: string[], cwd: string, severity: string, use continue; } let match = /^([^:]*: )?((.:)?[^:]*):(\d+)(:(\d+)?)?:(?:\w+:)? (.*)$/.exec(lines[i]); - if (!match) continue; + if (!match) { + if (printUnexpectedOutput) outputChannel.appendLine(lines[i]); + continue; + } let [_, __, file, ___, lineStr, ____, charStr, msg] = match; let line = +lineStr; file = path.resolve(cwd, file); @@ -91,55 +110,46 @@ export function check(filename: string, goConfig: vscode.WorkspaceConfiguration) let tmppath = path.normalize(path.join(os.tmpdir(), 'go-code-check')); let args = ['build']; if (!isMainPkg) { - args.push('- i'); + args.push('-i'); }; args = args.concat(['-o', tmppath, '-tags', buildTags, ...buildFlags, '.']); if (filename.match(/_test.go$/i)) { args = ['test', '-copybinary', '-o', tmppath, '-c', '-tags', buildTags, ...buildFlags, '.']; } runTool( - goRuntimePath, args, cwd, 'error', true, null, - `Cannot find ${goRuntimePath}` + true ).then(result => resolve(result), err => reject(err)); }); }); runningToolsPromises.push(buildPromise); } if (!!goConfig['lintOnSave']) { - let lintTool = getBinPath(goConfig['lintTool'] || 'golint'); + let lintTool = goConfig['lintTool'] || 'golint'; let lintFlags = goConfig['lintFlags'] || []; let args = [...lintFlags]; - if (lintTool === 'golint') { - args.push(filename); - } - runningToolsPromises.push(runTool( - lintTool, args, cwd, 'warning', - lintTool === 'golint', - lintTool === 'golint' ? 'golint' : null, - lintTool === 'golint' ? undefined : 'No "gometalinter" could be found. Install gometalinter to use this option.' + false, + lintTool )); } if (!!goConfig['vetOnSave']) { let vetFlags = goConfig['vetFlags'] || []; runningToolsPromises.push(runTool( - goRuntimePath, ['tool', 'vet', ...vetFlags, filename], cwd, 'warning', true, - null, - `Cannot find ${goRuntimePath}` + null )); } diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts index c12de2c92..46eda675e 100644 --- a/src/goInstallTools.ts +++ b/src/goInstallTools.ts @@ -47,6 +47,11 @@ function getTools(goVersion: SemVersion): { [key: string]: string } { tools['golint'] = 'github.com/golang/lint/golint'; tools['gotests'] = 'github.com/cweill/gotests/...'; } + + if (goConfig['lintTool'] === 'gometalinter') { + tools['gometalinter'] = 'github.com/alecthomas/gometalinter'; + } + return tools; } @@ -131,7 +136,7 @@ function installTools(goVersion: SemVersion, missing?: string[]) { }); } - // If the VSCODE_GOTOOLS environment variable is set, use + // If the VSCODE_GOTOOLS environment variable is set, use // its value as the GOPATH for the "go get" child precess. let toolsGoPath = process.env['VSCODE_GOTOOLS']; if (toolsGoPath) { @@ -153,9 +158,21 @@ function installTools(goVersion: SemVersion, missing?: string[]) { })); }, Promise.resolve([])).then(res => { outputChannel.appendLine(''); // Blank line for spacing + let allDoneMsg = 'All tools successfully installed. You\'re ready to Go :).'; let failures = res.filter(x => x != null); if (failures.length === 0) { - outputChannel.appendLine('All tools successfully installed. You\'re ready to Go :).'); + // Gometalinter needs to install all the linters it uses. + if (missing.indexOf('gometalinter') > -1) { + let gometalinterBinPath = getBinPath('gometalinter'); + outputChannel.appendLine('Installing linters to be used by gometalinter...'); + cp.execFile(gometalinterBinPath, ['--install'], { env }, (err, stdout, stderr) => { + if (!err) { + outputChannel.appendLine(`Installed all linters to be used by gometalinter.\n\n${allDoneMsg}`); + } + }); + } else { + outputChannel.appendLine(allDoneMsg); + } return; }