Skip to content

Commit b6fe8e2

Browse files
committed
[release] src/goEnvironmentStatus.ts: clear pre-installed terminal PATH mutation
Changes to vscode.EnvironmentVariableCollection persist across vscode sessions, so when we decide not to mutate PATH, we need to clear the preexisting changes. The new function 'clearGoRuntimeBaseFromPATH' reverses almost all of what addGoRuntimeBaseToPATH did on the persisted state. Manually tested by setting/unsetting "go.alternateTools". Also, fixes the case where 'go.alternateTools' is set as an alternate tool name rather than an absolute path - in that case, we search the alternate tool from PATH. In this case, the reason shouldn't be 'path'. Manually tested by setting "go.alternateTools": { "go": "mygo.sh" } where "mygo.sh" is another binary that exists in PATH and shells out go. In addition to this, this change fixes an exception thrown while calling updateIntegratedTerminal when no 'go' executable is found from the default PATH. In that case, getBinPathFromEnvVar returns null, and path.dirname throws an error for non-string params. This results in the failure of updating terminal's PATH change and the users will not see the picked go from the terminal. This is a bug preexisted before 0.17.1 Manually tested by launching code without go in PATH. Updates #679 Fixes #713 Change-Id: I240694cb4425e81998299ab38097393a0f3faf46 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/258557 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 1b82f49) Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/258797
1 parent c71e9ce commit b6fe8e2

File tree

3 files changed

+44
-15
lines changed

3 files changed

+44
-15
lines changed

src/goEnvironmentStatus.ts

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,16 @@ async function downloadGo(goOption: GoEnvironmentOption) {
277277
// PATH value cached before addGoRuntimeBaseToPath modified.
278278
let defaultPathEnv = '';
279279

280+
function pathEnvVarName(): string|undefined {
281+
if (process.env.hasOwnProperty('PATH')) {
282+
return 'PATH';
283+
} else if (process.platform === 'win32' && process.env.hasOwnProperty('Path')) {
284+
return 'Path';
285+
} else {
286+
return;
287+
}
288+
}
289+
280290
// addGoRuntimeBaseToPATH adds the given path to the front of the PATH environment variable.
281291
// It removes duplicates.
282292
// TODO: can we avoid changing PATH but utilize toolExecutionEnv?
@@ -285,12 +295,8 @@ export function addGoRuntimeBaseToPATH(newGoRuntimeBase: string) {
285295
return;
286296
}
287297

288-
let pathEnvVar: string;
289-
if (process.env.hasOwnProperty('PATH')) {
290-
pathEnvVar = 'PATH';
291-
} else if (process.platform === 'win32' && process.env.hasOwnProperty('Path')) {
292-
pathEnvVar = 'Path';
293-
} else {
298+
const pathEnvVar = pathEnvVarName();
299+
if (!pathEnvVar) {
294300
return;
295301
}
296302

@@ -331,14 +337,32 @@ export function addGoRuntimeBaseToPATH(newGoRuntimeBase: string) {
331337
process.env[pathEnvVar] = pathVars.join(path.delimiter);
332338
}
333339

340+
// Clear terminal PATH environment modification previously installed
341+
// using addGoRuntimeBaseToPATH.
342+
// In particular, changes to vscode.EnvironmentVariableCollection persist across
343+
// vscode sessions, so when we decide not to mutate PATH, we need to clear
344+
// the preexisting changes.
345+
export function clearGoRuntimeBaseFromPATH() {
346+
if (terminalCreationListener) {
347+
const l = terminalCreationListener;
348+
terminalCreationListener = undefined;
349+
l.dispose();
350+
}
351+
const pathEnvVar = pathEnvVarName();
352+
if (!pathEnvVar) {
353+
return;
354+
}
355+
environmentVariableCollection?.delete(pathEnvVar);
356+
}
357+
334358
/**
335359
* update the PATH variable in the given terminal to default to the currently selected Go
336360
*/
337361
export async function updateIntegratedTerminal(terminal: vscode.Terminal): Promise<void> {
338362
if (!terminal) { return; }
339363
const gorootBin = path.join(getCurrentGoRoot(), 'bin');
340-
const defaultGoRuntimeBin = path.dirname(getBinPathFromEnvVar('go', defaultPathEnv, false));
341-
if (gorootBin === defaultGoRuntimeBin) {
364+
const defaultGoRuntime = getBinPathFromEnvVar('go', defaultPathEnv, false);
365+
if (defaultGoRuntime && gorootBin === path.dirname(defaultGoRuntime)) {
342366
return;
343367
}
344368

src/goInstallTools.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { SemVer } from 'semver';
1212
import util = require('util');
1313
import vscode = require('vscode');
1414
import { toolExecutionEnvironment, toolInstallationEnvironment } from './goEnv';
15-
import { addGoRuntimeBaseToPATH, initGoStatusBar } from './goEnvironmentStatus';
15+
import { addGoRuntimeBaseToPATH, clearGoRuntimeBaseFromPATH, initGoStatusBar } from './goEnvironmentStatus';
1616
import { getLanguageServerToolPath } from './goLanguageServer';
1717
import { restartLanguageServer } from './goMain';
1818
import { hideGoStatus, outputChannel, showGoStatus } from './goStatus';
@@ -389,6 +389,9 @@ export function updateGoVarsFromConfig(): Promise<void> {
389389
// version of go than the system default found from PATH (or Path).
390390
if (why !== 'path') {
391391
addGoRuntimeBaseToPATH(path.join(getCurrentGoRoot(), 'bin'));
392+
} else {
393+
// clear pre-existing terminal PATH mutation logic set up by this extension.
394+
clearGoRuntimeBaseFromPATH();
392395
}
393396
initGoStatusBar();
394397
// TODO: restart language server or synchronize with language server update.

src/utils/pathUtils.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ let binPathCache: { [bin: string]: string } = {};
1818

1919
export const envPath = process.env['PATH'] || (process.platform === 'win32' ? process.env['Path'] : null);
2020

21-
export function getBinPathFromEnvVar(toolName: string, envVarValue: string, appendBinToPath: boolean): string {
21+
// find the tool's path from the given PATH env var, or null if the tool is not found.
22+
export function getBinPathFromEnvVar(toolName: string, envVarValue: string, appendBinToPath: boolean): string|null {
2223
toolName = correctBinname(toolName);
2324
if (envVarValue) {
2425
const paths = envVarValue.split(path.delimiter);
@@ -44,7 +45,7 @@ export function getBinPathWithPreferredGopathGoroot(
4445
return r.binPath;
4546
}
4647

47-
// Is same as getBinPAthWithPreferredGopathGoroot, but returns why the
48+
// Is same as getBinPathWithPreferredGopathGoroot, but returns why the
4849
// returned path was chosen.
4950
export function getBinPathWithPreferredGopathGorootWithExplanation(
5051
toolName: string,
@@ -64,10 +65,11 @@ export function getBinPathWithPreferredGopathGorootWithExplanation(
6465
}
6566

6667
const binname = alternateTool && !path.isAbsolute(alternateTool) ? alternateTool : toolName;
68+
const found = (why: string) => binname === toolName ? why : 'alternateTool';
6769
const pathFromGoBin = getBinPathFromEnvVar(binname, process.env['GOBIN'], false);
6870
if (pathFromGoBin) {
6971
binPathCache[toolName] = pathFromGoBin;
70-
return {binPath: pathFromGoBin, why: 'gobin'};
72+
return {binPath: pathFromGoBin, why: binname === toolName ? 'gobin' : 'alternateTool'};
7173
}
7274

7375
for (const preferred of preferredGopaths) {
@@ -76,7 +78,7 @@ export function getBinPathWithPreferredGopathGorootWithExplanation(
7678
const pathFrompreferredGoPath = getBinPathFromEnvVar(binname, preferred, true);
7779
if (pathFrompreferredGoPath) {
7880
binPathCache[toolName] = pathFrompreferredGoPath;
79-
return {binPath: pathFrompreferredGoPath, why: 'gopath'};
81+
return {binPath: pathFrompreferredGoPath, why: found('gopath')};
8082
}
8183
}
8284
}
@@ -85,14 +87,14 @@ export function getBinPathWithPreferredGopathGorootWithExplanation(
8587
const pathFromGoRoot = getBinPathFromEnvVar(binname, preferredGoroot || getCurrentGoRoot(), true);
8688
if (pathFromGoRoot) {
8789
binPathCache[toolName] = pathFromGoRoot;
88-
return {binPath: pathFromGoRoot, why: 'goroot'};
90+
return {binPath: pathFromGoRoot, why: found('goroot')};
8991
}
9092

9193
// Finally search PATH parts
9294
const pathFromPath = getBinPathFromEnvVar(binname, envPath, false);
9395
if (pathFromPath) {
9496
binPathCache[toolName] = pathFromPath;
95-
return {binPath: pathFromPath, why: 'path'};
97+
return {binPath: pathFromPath, why: found('path')};
9698
}
9799

98100
// Check default path for go

0 commit comments

Comments
 (0)