Skip to content

Commit 20ba7a5

Browse files
committed
[release] src/goInstallTools.ts: mutate PATH only when necessary
When the extension chooses a different version of go than the one from the system default - because the user has configured `go.goroot` or `go.alternateTools.go`, or used the `Go: Choose Go Environment` command - the extension mutates the `PATH` (or `Path` on windows) environment variable so all the underlying tools pick the same go version. It also changes the environment variable collection used in the integrated terminal so when the user invokes `go` from the terminal, they use the go version consistent with the extension. But this behavior can conflict with external version management software. Change the PATH environment only if the extension is configured to choose the go binary. Fixes #679. Update #544. Change-Id: I9f7acb26b752ed33dbde2b238a67ed09616b43e5 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/256938 Trust: Hyang-Ah Hana Kim <[email protected]> Run-TryBot: Hyang-Ah Hana Kim <[email protected]> TryBot-Result: kokoro <[email protected]> Reviewed-by: Suzy Mueller <[email protected]> (cherry picked from commit ab4b257) Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/258077
1 parent dfdd910 commit 20ba7a5

File tree

1 file changed

+74
-33
lines changed

1 file changed

+74
-33
lines changed

src/goInstallTools.ts

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
Tool,
2828
ToolAtVersion,
2929
} from './goTools';
30+
import { getFromWorkspaceState } from './stateUtils';
3031
import {
3132
getBinPath,
3233
getGoConfig,
@@ -36,7 +37,7 @@ import {
3637
GoVersion,
3738
rmdirRecursive,
3839
} from './util';
39-
import { envPath, getCurrentGoRoot, getToolFromToolPath, setCurrentGoRoot } from './utils/pathUtils';
40+
import { correctBinname, envPath, getCurrentGoRoot, getToolFromToolPath, setCurrentGoRoot } from './utils/pathUtils';
4041

4142
// declinedUpdates tracks the tools that the user has declined to update.
4243
const declinedUpdates: Tool[] = [];
@@ -342,10 +343,11 @@ export async function promptForUpdatingTool(toolName: string, newVersion?: SemVe
342343
}
343344

344345
export function updateGoVarsFromConfig(): Promise<void> {
345-
// FIXIT: if updateGoVarsFromConfig is called again after addGoRuntimeBaseToPATH sets PATH,
346-
// the go chosen by getBinPath based on PATH will not change.
347346
const goRuntimePath = getBinPath('go', false);
348-
if (!goRuntimePath) {
347+
348+
if (!goRuntimePath || !path.isAbsolute(goRuntimePath)) {
349+
// getBinPath returns the absolute path to the tool if it exists.
350+
// Otherwise, it may return the tool name (e.g. 'go').
349351
suggestDownloadGo();
350352
return Promise.reject();
351353
}
@@ -355,41 +357,80 @@ export function updateGoVarsFromConfig(): Promise<void> {
355357
['env', 'GOPATH', 'GOROOT', 'GOPROXY', 'GOBIN', 'GOMODCACHE'],
356358
{ env: toolExecutionEnvironment(), cwd: getWorkspaceFolderPath() },
357359
(err, stdout, stderr) => {
358-
if (err || stderr) {
359-
outputChannel.append(`Failed to run '${goRuntimePath} env: ${err}\n${stderr}`);
360-
outputChannel.show();
360+
if (err || stderr) {
361+
outputChannel.append(`Failed to run '${goRuntimePath} env: ${err}\n${stderr}`);
362+
outputChannel.show();
361363

362-
vscode.window.showErrorMessage(`Failed to run '${goRuntimePath} env. The config change may not be applied correctly.`);
363-
return reject();
364-
}
365-
const envOutput = stdout.split('\n');
366-
if (!process.env['GOPATH'] && envOutput[0].trim()) {
367-
process.env['GOPATH'] = envOutput[0].trim();
368-
}
369-
if (envOutput[1] && envOutput[1].trim()) {
370-
setCurrentGoRoot(envOutput[1].trim());
371-
}
372-
if (!process.env['GOPROXY'] && envOutput[2] && envOutput[2].trim()) {
373-
process.env['GOPROXY'] = envOutput[2].trim();
374-
}
375-
if (!process.env['GOBIN'] && envOutput[3] && envOutput[3].trim()) {
376-
process.env['GOBIN'] = envOutput[3].trim();
377-
}
378-
if (!process.env['GOMODCACHE'] && envOutput[4] && envOutput[4].trim()) {
379-
process.env['GOMODCACHE'] = envOutput[4].trim();
380-
}
364+
vscode.window.showErrorMessage(`Failed to run '${goRuntimePath} env. The config change may not be applied correctly.`);
365+
return reject();
366+
}
367+
const envOutput = stdout.split('\n');
368+
if (!process.env['GOPATH'] && envOutput[0].trim()) {
369+
process.env['GOPATH'] = envOutput[0].trim();
370+
}
371+
if (envOutput[1] && envOutput[1].trim()) {
372+
setCurrentGoRoot(envOutput[1].trim());
373+
}
374+
if (!process.env['GOPROXY'] && envOutput[2] && envOutput[2].trim()) {
375+
process.env['GOPROXY'] = envOutput[2].trim();
376+
}
377+
if (!process.env['GOBIN'] && envOutput[3] && envOutput[3].trim()) {
378+
process.env['GOBIN'] = envOutput[3].trim();
379+
}
380+
if (!process.env['GOMODCACHE'] && envOutput[4] && envOutput[4].trim()) {
381+
process.env['GOMODCACHE'] = envOutput[4].trim();
382+
}
381383

382-
// cgo, gopls, and other underlying tools will inherit the environment and attempt
383-
// to locate 'go' from the PATH env var.
384-
addGoRuntimeBaseToPATH(path.join(getCurrentGoRoot(), 'bin'));
385-
initGoStatusBar();
386-
// TODO: restart language server or synchronize with language server update.
384+
// cgo, gopls, and other underlying tools will inherit the environment and attempt
385+
// to locate 'go' from the PATH env var.
386+
// Update the PATH only if users configured to use a different
387+
// version of go than the system default.
388+
if (!!goPickedByExtension()) {
389+
addGoRuntimeBaseToPATH(path.join(getCurrentGoRoot(), 'bin'));
390+
}
391+
initGoStatusBar();
392+
// TODO: restart language server or synchronize with language server update.
387393

388-
return resolve();
389-
});
394+
return resolve();
395+
});
390396
});
391397
}
392398

399+
// The go command is picked up by searching directories in PATH by default.
400+
// But users can override it and force the extension to pick a different
401+
// one by configuring
402+
//
403+
// 1) with the go.environment.choose command, which stores the selection
404+
// in the workspace memento with the key 'selectedGo',
405+
// 2) with 'go.alternateTools': { 'go': ... } setting, or
406+
// 3) with 'go.goroot' setting
407+
//
408+
// goPickedByExtension returns the chosen path if the default path should
409+
// be overridden by above methods.
410+
// TODO: This logic is duplicated in getBinPath. Centralize this logic.
411+
function goPickedByExtension(): string | undefined {
412+
// getFromWorkspaceState('selectedGo')
413+
const selectedGoPath: string = getFromWorkspaceState('selectedGo')?.binpath;
414+
if (selectedGoPath) {
415+
return selectedGoPath;
416+
}
417+
418+
const cfg = getGoConfig();
419+
420+
// 'go.alternateTools.go'
421+
const alternateTools: { [key: string]: string } = cfg.get('alternateTools');
422+
const alternateToolPath: string = alternateTools['go'];
423+
if (alternateToolPath) {
424+
return alternateToolPath;
425+
}
426+
// 'go.goroot'
427+
const goRoot: string = cfg.get('goroot');
428+
if (goRoot) {
429+
return path.join(goRoot, 'bin', correctBinname('go'));
430+
}
431+
return undefined;
432+
}
433+
393434
let alreadyOfferedToInstallTools = false;
394435

395436
export async function offerToInstallTools() {

0 commit comments

Comments
 (0)