/*--------------------------------------------------------- | |
* Copyright (C) Microsoft Corporation. All rights reserved. | |
* Licensed under the MIT License. See License.txt in the project root for license information. | |
*--------------------------------------------------------*/ | |
import path = require('path'); | |
import vscode = require('vscode'); | |
import { vetDiagnosticCollection } from './goMain'; | |
import { diagnosticsStatusBarItem, outputChannel } from './goStatus'; | |
import { | |
getGoConfig, | |
getGoVersion, | |
getToolsEnvVars, | |
getWorkspaceFolderPath, | |
handleDiagnosticErrors, | |
ICheckResult, | |
resolvePath, | |
runTool | |
} from './util'; | |
/** | |
* Runs go vet in the current package or workspace. | |
*/ | |
export function vetCode(vetWorkspace?: boolean) { | |
const editor = vscode.window.activeTextEditor; | |
if (!editor && !vetWorkspace) { | |
vscode.window.showInformationMessage('No editor is active, cannot find current package to vet'); | |
return; | |
} | |
if (editor.document.languageId !== 'go' && !vetWorkspace) { | |
vscode.window.showInformationMessage( | |
'File in the active editor is not a Go file, cannot find current package to vet' | |
); | |
return; | |
} | |
const documentUri = editor ? editor.document.uri : null; | |
const goConfig = getGoConfig(documentUri); | |
outputChannel.clear(); // Ensures stale output from vet on save is cleared | |
diagnosticsStatusBarItem.show(); | |
diagnosticsStatusBarItem.text = 'Vetting...'; | |
goVet(documentUri, goConfig, vetWorkspace) | |
.then((warnings) => { | |
handleDiagnosticErrors(editor ? editor.document : null, warnings, vetDiagnosticCollection); | |
diagnosticsStatusBarItem.hide(); | |
}) | |
.catch((err) => { | |
vscode.window.showInformationMessage('Error: ' + err); | |
diagnosticsStatusBarItem.text = 'Vetting Failed'; | |
}); | |
} | |
/** | |
* Runs go vet or go tool vet and presents the output in the 'Go' channel and in the diagnostic collections. | |
* | |
* @param fileUri Document uri. | |
* @param goConfig Configuration for the Go extension. | |
* @param vetWorkspace If true vets code in all workspace. | |
*/ | |
export async function goVet( | |
fileUri: vscode.Uri, | |
goConfig: vscode.WorkspaceConfiguration, | |
vetWorkspace?: boolean | |
): Promise<ICheckResult[]> { | |
epoch++; | |
const closureEpoch = epoch; | |
if (tokenSource) { | |
if (running) { | |
tokenSource.cancel(); | |
} | |
tokenSource.dispose(); | |
} | |
tokenSource = new vscode.CancellationTokenSource(); | |
const currentWorkspace = getWorkspaceFolderPath(fileUri); | |
const cwd = vetWorkspace && currentWorkspace ? currentWorkspace : path.dirname(fileUri.fsPath); | |
if (!path.isAbsolute(cwd)) { | |
return Promise.resolve([]); | |
} | |
const vetFlags: string[] = goConfig['vetFlags'] || []; | |
const vetEnv = Object.assign({}, getToolsEnvVars()); | |
const args: string[] = []; | |
vetFlags.forEach((flag) => { | |
if (flag.startsWith('--vettool=') || flag.startsWith('-vettool=')) { | |
let vetToolPath = flag.substr(flag.indexOf('=') + 1).trim(); | |
if (!vetToolPath) { | |
return; | |
} | |
vetToolPath = resolvePath(vetToolPath); | |
args.push(`${flag.substr(0, flag.indexOf('=') + 1)}${vetToolPath}`); | |
return; | |
} | |
args.push(flag); | |
}); | |
const goVersion = await getGoVersion(); | |
const tagsArg = []; | |
if (goConfig['buildTags'] && vetFlags.indexOf('-tags') === -1) { | |
tagsArg.push('-tags'); | |
tagsArg.push(goConfig['buildTags']); | |
} | |
let vetArgs = ['vet', ...args, ...tagsArg, vetWorkspace ? './...' : '.']; | |
if (goVersion.lt('1.10') && args.length) { | |
vetArgs = ['tool', 'vet', ...args, ...tagsArg, '.']; | |
} | |
outputChannel.appendLine(`Starting "go vet" under the folder ${cwd}`); | |
running = true; | |
return runTool(vetArgs, cwd, 'warning', true, null, vetEnv, false, tokenSource.token).then((result) => { | |
if (closureEpoch === epoch) { | |
running = false; | |
} | |
return result; | |
}); | |
} | |
let epoch = 0; | |
let tokenSource: vscode.CancellationTokenSource; | |
let running = false; |