diff --git a/src/goImport.ts b/src/goImport.ts index 20f025cce..b30bd7521 100644 --- a/src/goImport.ts +++ b/src/goImport.ts @@ -8,9 +8,9 @@ import vscode = require('vscode'); import cp = require('child_process'); import { getBinPath } from './goPath'; -import { parseFilePrelude } from './util'; +import { parseFilePrelude, isVendorSupported } from './util'; import { documentSymbols } from './goOutline'; -import { promptForMissingTool, isVendorSupported } from './goInstallTools'; +import { promptForMissingTool } from './goInstallTools'; import path = require('path'); export function listPackages(excludeImportedPkgs: boolean = false): Thenable { diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts index e38883f25..25e1cb3d0 100644 --- a/src/goInstallTools.ts +++ b/src/goInstallTools.ts @@ -11,19 +11,13 @@ import path = require('path'); import os = require('os'); import cp = require('child_process'); import { showGoStatus, hideGoStatus } from './goStatus'; -import { getBinPath, getGoRuntimePath } from './goPath'; +import { getBinPath } from './goPath'; import { outputChannel } from './goStatus'; +import { getGoVersion, SemVersion, isVendorSupported } from './util'; -interface SemVersion { - major: number; - minor: number; -} - -let goVersion: SemVersion = null; -let vendorSupport: boolean = null; let updatesDeclinedTools: string[] = []; -function getTools(): { [key: string]: string } { +function getTools(goVersion: SemVersion): { [key: string]: string } { let goConfig = vscode.workspace.getConfiguration('go'); let tools: { [key: string]: string } = { 'gocode': 'github.com/nsf/gocode', @@ -42,8 +36,8 @@ function getTools(): { [key: string]: string } { 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))) { + // golint and gotests are not supported in go1.5 + if (!goVersion || (goVersion.major > 1 || (goVersion.major === 1 && goVersion.minor > 5))) { tools['golint'] = 'github.com/golang/lint/golint'; tools['gotests'] = 'github.com/cweill/gotests/...'; } @@ -51,13 +45,13 @@ function getTools(): { [key: string]: string } { } export function installAllTools() { - getGoVersion().then(() => installTools()); + getGoVersion().then((goVersion) => installTools(goVersion)); } export function promptForMissingTool(tool: string) { - getGoVersion().then(() => { - if (goVersion.major === 1 && goVersion.minor < 6) { + getGoVersion().then((goVersion) => { + if (goVersion && goVersion.major === 1 && goVersion.minor < 6) { if (tool === 'golint') { vscode.window.showInformationMessage('golint no longer supports go1.5, update your settings to use gometalinter as go.lintTool and install gometalinter'); return; @@ -68,11 +62,11 @@ export function promptForMissingTool(tool: string) { } } - vscode.window.showInformationMessage(`The "${tool}" command is not available. Use "go get -v ${getTools()[tool]}" to install.`, 'Install All', 'Install').then(selected => { + vscode.window.showInformationMessage(`The "${tool}" command is not available. Use "go get -v ${getTools(goVersion)[tool]}" to install.`, 'Install All', 'Install').then(selected => { if (selected === 'Install') { - installTools([tool]); + installTools(goVersion, [tool]); } else if (selected === 'Install All') { - getMissingTools().then(installTools); + getMissingTools(goVersion).then((missing) => installTools(goVersion, missing)); hideGoStatus(); } }); @@ -84,12 +78,14 @@ export function promptForUpdatingTool(tool: string) { if (updatesDeclinedTools.indexOf(tool) > -1) { return; } - vscode.window.showInformationMessage(`The Go extension is better with the latest version of "${tool}". Use "go get -u -v ${getTools()[tool]}" to update`, 'Update').then(selected => { - if (selected === 'Update') { - installTools([tool]); - } else { - updatesDeclinedTools.push(tool); - } + getGoVersion().then((goVersion) => { + vscode.window.showInformationMessage(`The Go extension is better with the latest version of "${tool}". Use "go get -u -v ${getTools(goVersion)[tool]}" to update`, 'Update').then(selected => { + if (selected === 'Update') { + installTools(goVersion, [tool]); + } else { + updatesDeclinedTools.push(tool); + } + }); }); } @@ -98,8 +94,8 @@ export function promptForUpdatingTool(tool: string) { * * @param string[] array of tool names to be installed */ -function installTools(missing?: string[]) { - let tools = getTools(); +function installTools(goVersion: SemVersion, missing?: string[]) { + let tools = getTools(goVersion); if (!missing) { missing = Object.keys(tools); } @@ -169,21 +165,24 @@ export function setupGoPathAndOfferToInstallTools() { return; } - getMissingTools().then(missing => { - if (missing.length > 0) { - showGoStatus('Analysis Tools Missing', 'go.promptforinstall', 'Not all Go tools are available on the GOPATH'); - vscode.commands.registerCommand('go.promptforinstall', () => { - promptForInstall(missing); - hideGoStatus(); - }); - } + getGoVersion().then(goVersion => { + getMissingTools(goVersion).then(missing => { + if (missing.length > 0) { + showGoStatus('Analysis Tools Missing', 'go.promptforinstall', 'Not all Go tools are available on the GOPATH'); + vscode.commands.registerCommand('go.promptforinstall', () => { + promptForInstall(goVersion, missing); + hideGoStatus(); + }); + } + }); }); - function promptForInstall(missing: string[]) { + + function promptForInstall(goVersion: SemVersion, missing: string[]) { let item = { title: 'Install', command() { - installTools(missing); + installTools(goVersion, missing); } }; vscode.window.showInformationMessage('Some Go analysis tools are missing from your GOPATH. Would you like to install them?', item).then(selection => { @@ -194,65 +193,22 @@ export function setupGoPathAndOfferToInstallTools() { } } -function getMissingTools(): Promise { - 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; +function getMissingTools(goVersion: SemVersion): Promise { + let keys = Object.keys(getTools(goVersion)); + 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; }); } -export function getGoVersion(): Promise { - let goRuntimePath = getGoRuntimePath(); - if (!goRuntimePath) { - vscode.window.showInformationMessage('Cannot find "go" binary. Update PATH or GOROOT appropriately'); - return Promise.resolve(null); - } - if (goVersion) { - return Promise.resolve(goVersion); - } - return new Promise((resolve, reject) => { - cp.execFile(goRuntimePath, ['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); - }); - }); -} -export function isVendorSupported(): Promise { - if (vendorSupport != null) { - return Promise.resolve(vendorSupport); - } - return getGoVersion().then(version => { - switch (version.major) { - case 0: - vendorSupport = false; - break; - case 1: - vendorSupport = (version.minor > 5 || (version.minor === 5 && process.env['GO15VENDOREXPERIMENT'] === '1')) ? true : false; - break; - default: - vendorSupport = true; - break; - } - return vendorSupport; - }); -} diff --git a/src/util.ts b/src/util.ts index 246c77d8c..c66a4de30 100644 --- a/src/util.ts +++ b/src/util.ts @@ -3,8 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------*/ -import { TextDocument, Position } from 'vscode'; +import { TextDocument, Position, window } from 'vscode'; import path = require('path'); +import { getGoRuntimePath } from './goPath'; +import cp = require('child_process'); + +export interface SemVersion { + major: number; + minor: number; +} + +let goVersion: SemVersion = null; +let vendorSupport: boolean = null; export function byteOffsetAt(document: TextDocument, position: Position): number { let offset = document.offsetAt(position); @@ -96,6 +106,62 @@ export function canonicalizeGOPATHPrefix(filename: string): string { return filename; } +/** + * Gets version of Go based on the output of the command `go version`. + * Returns null if go is being used from source/tip in which case `go version` will not return release tag like go1.6.3 + */ +export function getGoVersion(): Promise { + let goRuntimePath = getGoRuntimePath(); + + if (!goRuntimePath) { + window.showInformationMessage('Cannot find "go" binary. Update PATH or GOROOT appropriately'); + return Promise.resolve(null); + } + + if (goVersion) { + return Promise.resolve(goVersion); + } + return new Promise((resolve, reject) => { + cp.execFile(goRuntimePath, ['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); + }); + }); +} + +/** + * Returns boolean denoting if current version of Go supports vendoring + */ +export function isVendorSupported(): Promise { + if (vendorSupport != null) { + return Promise.resolve(vendorSupport); + } + return getGoVersion().then(version => { + if (!version) { + return process.env['GO15VENDOREXPERIMENT'] === '0' ? false : true; + } + + switch (version.major) { + case 0: + vendorSupport = false; + break; + case 1: + vendorSupport = (version.minor > 6 || ((version.minor === 5 || version.minor === 6) && process.env['GO15VENDOREXPERIMENT'] === '1')) ? true : false; + break; + default: + vendorSupport = true; + break; + } + return vendorSupport; + }); +} + export function random(low: number, high: number): number { return Math.floor(Math.random() * (high - low) + low); } diff --git a/test/go.test.ts b/test/go.test.ts index bf98d0ba6..bb761cb9c 100644 --- a/test/go.test.ts +++ b/test/go.test.ts @@ -15,12 +15,11 @@ 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'; +import { getGoVersion, isVendorSupported } from '../src/util'; import { documentSymbols } from '../src/goOutline'; import { listPackages } from '../src/goImport'; import { generateTestCurrentFile, generateTestCurrentPackage } from '../src/goGenerateTests'; import { getBinPath } from '../src/goPath'; -import { isVendorSupported } from '../src/goInstallTools'; suite('Go Extension Tests', () => { let gopath = process.env['GOPATH'];