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 2 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
117 changes: 35 additions & 82 deletions src/goInstallTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,11 @@ 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;

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 @@ -41,22 +34,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 @@ -67,11 +60,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,8 +77,8 @@ export function promptForMissingTool(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 @@ -155,21 +148,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 @@ -180,65 +176,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 @@ -94,4 +104,60 @@ 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;
});
}
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