diff --git a/.travis.yml b/.travis.yml index 8c635458d..abfd1e12d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ install: - npm run vscode:prepublish - go get -u -v github.com/nsf/gocode - go get -u -v github.com/rogpeppe/godef - - go get -u -v github.com/golang/lint/golint + - if [[ "$(go version)" =~ "go version go1.5" ]]; then echo cannot get golint; else go get -u -v github.com/golang/lint/golint; fi - go get -u -v github.com/lukehoban/go-outline - go get -u -v sourcegraph.com/sqs/goreturns - go get -u -v golang.org/x/tools/cmd/gorename diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts index 99aa4b9e6..21e5b0772 100644 --- a/src/goInstallTools.ts +++ b/src/goInstallTools.ts @@ -11,38 +11,76 @@ import path = require('path'); import os = require('os'); import cp = require('child_process'); import { showGoStatus, hideGoStatus } from './goStatus'; -import { getBinPath } from './goPath'; +import { getBinPath, getGoRuntimePath } from './goPath'; import { outputChannel } from './goStatus'; -let tools: { [key: string]: string } = { - 'gocode': 'github.com/nsf/gocode', - 'goreturns': 'sourcegraph.com/sqs/goreturns', - 'gopkgs': 'github.com/tpng/gopkgs', - 'godef': 'github.com/rogpeppe/godef', - 'golint': 'github.com/golang/lint/golint', - 'go-outline': 'github.com/lukehoban/go-outline', - 'go-symbols': 'github.com/newhook/go-symbols', - 'guru': 'golang.org/x/tools/cmd/guru', - 'gorename': 'golang.org/x/tools/cmd/gorename', - 'goimports': 'golang.org/x/tools/cmd/goimports' -}; +interface SemVersion { + major: number; + minor: number; +} + +let goVersion: SemVersion = null; + +function getTools(): { [key: string]: string } { + let goConfig = vscode.workspace.getConfiguration('go'); + let tools: { [key: string]: string } = { + 'gocode': 'github.com/nsf/gocode', + 'gopkgs': 'github.com/tpng/gopkgs', + 'godef': 'github.com/rogpeppe/godef', + 'go-outline': 'github.com/lukehoban/go-outline', + 'go-symbols': 'github.com/newhook/go-symbols', + 'guru': 'golang.org/x/tools/cmd/guru', + 'gorename': 'golang.org/x/tools/cmd/gorename' + }; + + // Install the formattool that was chosen by the user + if (goConfig['formatTool'] === 'goimports') { + tools['goimports'] = 'golang.org/x/tools/cmd/goimports'; + } else if (goConfig['formatTool'] === 'goreturns') { + tools['goreturns'] = 'sourcegraph.com/sqs/goreturns'; + } + + // golint is no longer supported in go1.5 + if (goVersion && (goVersion.major > 1 || (goVersion.major === 1 && goVersion.minor > 5))) { + tools['golint'] = 'github.com/golang/lint/golint'; + } + return tools; +} export function installAllTools() { - installTools(Object.keys(tools)); + getGoVersion().then(() => installTools()); } export function promptForMissingTool(tool: string) { - vscode.window.showInformationMessage(`The "${tool}" command is not available. Use "go get -v ${tools[tool]}" to install.`, 'Install All', 'Install').then(selected => { - if (selected === 'Install') { - installTools([tool]); - } else if (selected === 'Install All') { - getMissingTools().then(installTools); - hideGoStatus(); + + getGoVersion().then(() => { + if (tool === 'golint' && goVersion.major === 1 && goVersion.minor < 6) { + vscode.window.showInformationMessage('golint no longer supports go1.5, update your settings to use gometalinter as go.lintTool and install gometalinter'); + return; } + + vscode.window.showInformationMessage(`The "${tool}" command is not available. Use "go get -v ${getTools()[tool]}" to install.`, 'Install All', 'Install').then(selected => { + if (selected === 'Install') { + installTools([tool]); + } else if (selected === 'Install All') { + getMissingTools().then(installTools); + hideGoStatus(); + } + }); }); + } -export function installTools(missing: string[]) { +/** + * Installs given array of missing tools. If no input is given, the all tools are installed + * + * @param string[] array of tool names to be installed + */ +function installTools(missing?: string[]) { + let tools = getTools(); + if (!missing) { + missing = Object.keys(tools); + } outputChannel.show(); outputChannel.clear(); outputChannel.appendLine('Installing ' + missing.length + ' tools'); @@ -134,14 +172,34 @@ export function setupGoPathAndOfferToInstallTools() { } function getMissingTools(): Promise { - let keys = Object.keys(tools); - return Promise.all(keys.map(tool => new Promise((resolve, reject) => { - let toolPath = getBinPath(tool); - fs.exists(toolPath, exists => { - resolve(exists ? null : tool); + return getGoVersion().then(() => { + let keys = Object.keys(getTools()); + return Promise.all(keys.map(tool => new Promise((resolve, reject) => { + let toolPath = getBinPath(tool); + fs.exists(toolPath, exists => { + resolve(exists ? null : tool); + }); + }))).then(res => { + let missing = res.filter(x => x != null); + return missing; }); - }))).then(res => { - let missing = res.filter(x => x != null); - return missing; }); } + +export function getGoVersion(): Promise { + if (goVersion) { + return Promise.resolve(goVersion); + } + return new Promise((resolve, reject) => { + cp.execFile(getGoRuntimePath(), ['version'], {}, (err, stdout, stderr) => { + let matches = /go version go(\d).(\d).*/.exec(stdout); + if (matches) { + goVersion = { + major: parseInt(matches[1]), + minor: parseInt(matches[2]) + }; + } + return resolve(goVersion); + }); + }); +} \ No newline at end of file diff --git a/test/go.test.ts b/test/go.test.ts index e887314f0..72a814b2c 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -15,6 +15,7 @@ import cp = require('child_process'); import { getEditsFromUnifiedDiffStr, getEdits } from '../src/diffUtils'; import jsDiff = require('diff'); import { testCurrentFile } from '../src/goTest'; +import { getGoVersion } from '../src/goInstallTools'; suite('Go Extension Tests', () => { let gopath = process.env['GOPATH']; @@ -122,15 +123,23 @@ encountered. // { line: 7, severity: 'warning', msg: 'no formatting directive in Printf call' }, { line: 11, severity: 'error', msg: 'undefined: prin' }, ]; - check(path.join(fixturePath, 'errorsTest', 'errors.go'), config).then(diagnostics => { - let sortedDiagnostics = diagnostics.sort((a, b) => a.line - b.line); - for (let i in expected) { - assert.equal(sortedDiagnostics[i].line, expected[i].line); - assert.equal(sortedDiagnostics[i].severity, expected[i].severity); - assert.equal(sortedDiagnostics[i].msg, expected[i].msg); + getGoVersion().then(version => { + if (version.major === 1 && version.minor === 5) { + // golint is not supported in Go 1.5, so skip the test + return Promise.resolve(); } - assert.equal(sortedDiagnostics.length, expected.length, `too many errors ${JSON.stringify(sortedDiagnostics)}`); + return check(path.join(fixturePath, 'errorsTest', 'errors.go'), config).then(diagnostics => { + let sortedDiagnostics = diagnostics.sort((a, b) => a.line - b.line); + for (let i in expected) { + assert.equal(sortedDiagnostics[i].line, expected[i].line); + assert.equal(sortedDiagnostics[i].severity, expected[i].severity); + assert.equal(sortedDiagnostics[i].msg, expected[i].msg); + } + assert.equal(sortedDiagnostics.length, expected.length, `too many errors ${JSON.stringify(sortedDiagnostics)}`); + }); + }).then(() => done(), done); + }); test('Gometalinter error checking', (done) => {