Skip to content

Commit

Permalink
src/goEnvironmentStatus.ts: update go.alternateTools upon Go switch
Browse files Browse the repository at this point in the history
This CL addresses the fifth item in the general outline below:

1. Create status bar item for switching Go binary (not implemented)
2. Create command palette menu for choosing the Go binary
3. Track the currently selected Go binary using workspace context
4. Show versions of Go that are not installed and allow them to be
selected and installed
5. Update workspace state to use settings.json instead
6. Ensure new integrated terminals use the selected environment
7. Detect if Go is not installed and prompt to install it
8. Detect if user has the latest version of Go installed and prompt them
to install it
9. Cache Go paths upon extension initialization for faster menu loading

This CL makes the Go statusbar item update `go.alternateTools` in
settings.json when the
user selects a Go version, which makes the changes take effect.

Change-Id: Ib5c387728b9b9ac12428cc074910d9202d64fd15
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/240279
Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
  • Loading branch information
mcjcloud authored and hyangah committed Jun 30, 2020
1 parent 4424140 commit 0c374ff
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 40 deletions.
52 changes: 23 additions & 29 deletions src/goEnvironmentStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ import vscode = require('vscode');
import WebRequest = require('web-request');

import { toolInstallationEnvironment } from './goEnv';
import { updateGoVarsFromConfig } from './goInstallTools';
import { getCurrentGoRoot } from './goPath';
import { getActiveGoRoot } from './goInstallTools';
import { outputChannel } from './goStatus';
import { getFromWorkspaceState, updateWorkspaceState } from './stateUtils';
import { getBinPath, getGoVersion } from './util';
import { getBinPath, getGoConfig, getGoVersion } from './util';

export class GoEnvironmentOption {
public static fromQuickPickItem({ description, label }: vscode.QuickPickItem): GoEnvironmentOption {
Expand Down Expand Up @@ -48,7 +46,6 @@ export async function initGoStatusBar() {
// set Go version and command
const version = await getGoVersion();
const goOption = new GoEnvironmentOption(version.binaryPath, formatGoVersion(version.format()));
await setSelectedGo(goOption);

hideGoStatusBar();
goEnvStatusbarItem.text = goOption.label;
Expand Down Expand Up @@ -91,7 +88,7 @@ export async function chooseGoEnvironment() {
return;
}

// fetch default go and uninstalled gos
// fetch default go and uninstalled go versions
let defaultOption: GoEnvironmentOption;
let uninstalledOptions: GoEnvironmentOption[];
let goSDKOptions: GoEnvironmentOption[];
Expand Down Expand Up @@ -127,7 +124,7 @@ export async function chooseGoEnvironment() {

// update currently selected go
try {
await setSelectedGo(GoEnvironmentOption.fromQuickPickItem(selection));
await setSelectedGo(GoEnvironmentOption.fromQuickPickItem(selection), vscode.ConfigurationTarget.Workspace);
vscode.window.showInformationMessage(`Switched to ${selection.label}`);
} catch (e) {
vscode.window.showErrorMessage(e.message);
Expand All @@ -137,8 +134,11 @@ export async function chooseGoEnvironment() {
/**
* update the selected go path and label in the workspace state
*/
export async function setSelectedGo(selectedGo: GoEnvironmentOption) {
export async function setSelectedGo(selectedGo: GoEnvironmentOption, scope: vscode.ConfigurationTarget) {
const execFile = promisify(cp.execFile);

const goConfig = getGoConfig();
const alternateTools: any = goConfig.get('alternateTools') || {};
// if the selected go version is not installed, install it
if (selectedGo.binpath.startsWith('go get')) {
// start a loading indicator
Expand Down Expand Up @@ -187,32 +187,36 @@ export async function setSelectedGo(selectedGo: GoEnvironmentOption) {
const subdirs = await fs.readdir(sdkPath);
const dir = subdirs.find((subdir) => subdir === newExecutableName);
if (!dir) {
outputChannel.appendLine(`Could not install Go to directory: ${dir}`);
outputChannel.appendLine('Could not find newly downloaded Go');
throw new Error('Could not install Go version.');
}

outputChannel.appendLine('Updating selected Go version.');
await updateWorkspaceState('selected-go', new GoEnvironmentOption(
path.join(sdkPath, dir, 'bin', 'go'),
selectedGo.label
));
const binpath = path.join(sdkPath, dir, 'bin', 'go');
const newAlternateTools = {
...alternateTools,
go: binpath,
};
await goConfig.update('alternateTools', newAlternateTools, scope);
goEnvStatusbarItem.text = selectedGo.label;
outputChannel.appendLine('Success!');
});
} else {
await updateWorkspaceState('selected-go', selectedGo);
const newAlternateTools = {
...alternateTools,
go: selectedGo.binpath,
};
await goConfig.update('alternateTools', newAlternateTools, scope);
goEnvStatusbarItem.text = selectedGo.label;
}

// TODO: restart language server when the Go binary is switched
// TODO: determine if changes to settings.json need to be made
// TODO: restart language server if needed
}

/**
* retreive the current selected Go from the workspace state
*/
export async function getSelectedGo(): Promise<GoEnvironmentOption> {
return await getFromWorkspaceState('selected-go');
const goVersion = await getGoVersion();
return new GoEnvironmentOption(goVersion.binaryPath, formatGoVersion(goVersion.format()));
}

/**
Expand All @@ -222,16 +226,6 @@ export function getGoEnvironmentStatusbarItem(): vscode.StatusBarItem {
return goEnvStatusbarItem;
}

export async function getActiveGoRoot(): Promise<string | undefined> {
// look for current current go binary
let goroot = getCurrentGoRoot();
if (!goroot) {
await updateGoVarsFromConfig();
goroot = getCurrentGoRoot();
}
return goroot || undefined;
}

export function formatGoVersion(version: string): string {
const versionWords = version.split(' ');
if (versionWords[0] === 'devel') {
Expand Down
10 changes: 10 additions & 0 deletions src/goInstallTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,3 +493,13 @@ function getMissingTools(goVersion: GoVersion): Promise<Tool[]> {
return res.filter((x) => x != null);
});
}

export async function getActiveGoRoot(): Promise<string | undefined> {
// look for current current go binary
let goroot = getCurrentGoRoot();
if (!goroot) {
await updateGoVarsFromConfig();
goroot = getCurrentGoRoot();
}
return goroot || undefined;
}
72 changes: 61 additions & 11 deletions test/integration/statusbar.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import * as os from 'os';
import * as path from 'path';
import * as sinon from 'sinon';
import * as util from 'util';
import { WorkspaceConfiguration } from 'vscode';
import * as vscode from 'vscode';

import {
disposeGoStatusBar,
Expand Down Expand Up @@ -52,34 +52,84 @@ describe('#initGoStatusBar()', function () {

describe('#setSelectedGo()', function () {
this.timeout(20000);
let sandbox: sinon.SinonSandbox | undefined;
let goOption: GoEnvironmentOption;
let defaultGoConfig: vscode.WorkspaceConfiguration;

this.beforeAll(async () => {
defaultGoConfig = ourutil.getGoConfig();
});

this.beforeEach(async () => {
goOption = await getSelectedGo();
sandbox = sinon.createSandbox();
});
this.afterEach(async () => {
await setSelectedGo(goOption);
await setSelectedGo(goOption, vscode.ConfigurationTarget.Workspace);
sandbox.restore();
});

it('should update the selected Go in workspace context', async () => {
const testOption = new GoEnvironmentOption('testpath', 'testlabel');
await setSelectedGo(testOption);
const setOption = await getSelectedGo();
assert.ok(setOption.label === 'testlabel' && setOption.binpath === 'testpath', 'Selected go was not set properly');
it('should update the workspace settings.json', async () => {
let tmpAltToolsWorkspace: any = {};
let tmpAltToolsGlobal: any = {};
const getGoConfigStub = sandbox.stub(ourutil, 'getGoConfig').returns({
get: (s: string) => {
if (s === 'alternateTools') { return tmpAltToolsWorkspace || tmpAltToolsGlobal; }
return defaultGoConfig.get(s);
},
update: (key: string, value: any, scope: vscode.ConfigurationTarget) => {
if (key === 'alternateTools') {
if (scope === vscode.ConfigurationTarget.Global) {
tmpAltToolsGlobal = value;
} else {
tmpAltToolsWorkspace = value;
}
}
},
} as vscode.WorkspaceConfiguration);

// set workspace setting
const workspaceTestOption = new GoEnvironmentOption('workspacetestpath', 'testlabel');
await setSelectedGo(workspaceTestOption, vscode.ConfigurationTarget.Workspace);

// check that the stub was called
sandbox.assert.calledWith(getGoConfigStub);

// check that the new config is set
assert.equal(tmpAltToolsWorkspace['go'], 'workspacetestpath');
});

it('should download an uninstalled version of Go', async () => {
if (!!process.env['VSCODEGO_BEFORE_RELEASE_TESTS']) {
return;
}

let tmpAltToolsWorkspace = {};
let tmpAltToolsGlobal = {};
const getGoConfigStub = sandbox.stub(ourutil, 'getGoConfig').returns({
get: (s: string) => {
if (s === 'alternateTools') { return tmpAltToolsWorkspace || tmpAltToolsGlobal; }
return defaultGoConfig.get(s);
},
update: (key: string, value: any, scope: vscode.ConfigurationTarget) => {
if (key === 'alternateTools') {
if (scope === vscode.ConfigurationTarget.Global) {
tmpAltToolsGlobal = value;
} else {
tmpAltToolsWorkspace = value;
}
}
},
} as vscode.WorkspaceConfiguration);

// setup tmp home directory for sdk installation
const envCache = Object.assign({}, process.env);
process.env.HOME = os.tmpdir();

// set selected go as a version to download
const option = new GoEnvironmentOption('go get golang.org/dl/go1.13.12', 'Go 1.13.12');
await setSelectedGo(option);
await setSelectedGo(option, vscode.ConfigurationTarget.Workspace);
sandbox.assert.calledWith(getGoConfigStub);

// the temp sdk directory should now contain go1.13.12
const subdirs = await fs.readdir(path.join(os.tmpdir(), 'sdk'));
Expand All @@ -93,7 +143,7 @@ describe('#setSelectedGo()', function () {
describe('#updateGoVarsFromConfig()', function () {
this.timeout(10000);

let defaultGoConfig: WorkspaceConfiguration | undefined;
let defaultGoConfig: vscode.WorkspaceConfiguration | undefined;
let tmpRoot: string | undefined;
let tmpRootBin: string | undefined;
let sandbox: sinon.SinonSandbox | undefined;
Expand Down Expand Up @@ -155,7 +205,7 @@ describe('#updateGoVarsFromConfig()', function () {
if (s === 'goroot') { return tmpRoot; }
return defaultGoConfig.get(s);
},
} as WorkspaceConfiguration);
} as vscode.WorkspaceConfiguration);

// adjust the fake go binary's behavior.
process.env['FAKEGOROOT'] = tmpRoot;
Expand All @@ -181,7 +231,7 @@ describe('#updateGoVarsFromConfig()', function () {
}
return defaultGoConfig.get(s);
},
} as WorkspaceConfiguration);
} as vscode.WorkspaceConfiguration);

process.env['FAKEGOROOT'] = tmpRoot;
process.env['FAKEGOVERSION'] = 'go version go3.0.0 darwin/amd64';
Expand Down

0 comments on commit 0c374ff

Please sign in to comment.