Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Fix for when Go is used from source without release tag #549

Merged
merged 3 commits into from
Oct 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/goImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string[]> {
Expand Down
130 changes: 43 additions & 87 deletions src/goInstallTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -42,22 +36,22 @@ 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/...';
}
return tools;
}

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;
Expand All @@ -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();
}
});
Expand All @@ -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);
}
});
});
}

Expand All @@ -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);
}
Expand Down Expand Up @@ -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 => {
Expand All @@ -194,65 +193,22 @@ export function setupGoPathAndOfferToInstallTools() {
}
}

function getMissingTools(): Promise<string[]> {
return getGoVersion().then(() => {
let keys = Object.keys(getTools());
return Promise.all<string>(keys.map(tool => new Promise<string>((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<string[]> {
let keys = Object.keys(getTools(goVersion));
return Promise.all<string>(keys.map(tool => new Promise<string>((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<SemVersion> {
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<SemVersion>((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<boolean> {
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;
});
}

68 changes: 67 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<SemVersion> {
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<SemVersion>((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<boolean> {
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);
}
3 changes: 1 addition & 2 deletions test/go.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'];
Expand Down