Skip to content

Commit 1b82f49

Browse files
committed
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]>
1 parent 9bf9d64 commit 1b82f49

File tree

3 files changed

+45
-15
lines changed

3 files changed

+45
-15
lines changed

src/goEnvironmentStatus.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -303,19 +303,25 @@ async function downloadGo(goOption: GoEnvironmentOption) {
303303
// PATH value cached before addGoRuntimeBaseToPath modified.
304304
let defaultPathEnv = '';
305305

306+
function pathEnvVarName(): string|undefined {
307+
if (process.env.hasOwnProperty('PATH')) {
308+
return 'PATH';
309+
} else if (process.platform === 'win32' && process.env.hasOwnProperty('Path')) {
310+
return 'Path';
311+
} else {
312+
return;
313+
}
314+
}
315+
306316
// addGoRuntimeBaseToPATH adds the given path to the front of the PATH environment variable.
307317
// It removes duplicates.
308318
// TODO: can we avoid changing PATH but utilize toolExecutionEnv?
309319
export function addGoRuntimeBaseToPATH(newGoRuntimeBase: string) {
310320
if (!newGoRuntimeBase) {
311321
return;
312322
}
313-
let pathEnvVar: string;
314-
if (process.env.hasOwnProperty('PATH')) {
315-
pathEnvVar = 'PATH';
316-
} else if (process.platform === 'win32' && process.env.hasOwnProperty('Path')) {
317-
pathEnvVar = 'Path';
318-
} else {
323+
const pathEnvVar = pathEnvVarName();
324+
if (!pathEnvVar) {
319325
logVerbose(`couldn't find PATH property in process.env`);
320326
return;
321327
}
@@ -359,14 +365,33 @@ export function addGoRuntimeBaseToPATH(newGoRuntimeBase: string) {
359365
process.env[pathEnvVar] = pathVars.join(path.delimiter);
360366
}
361367

368+
// Clear terminal PATH environment modification previously installed
369+
// using addGoRuntimeBaseToPATH.
370+
// In particular, changes to vscode.EnvironmentVariableCollection persist across
371+
// vscode sessions, so when we decide not to mutate PATH, we need to clear
372+
// the preexisting changes.
373+
export function clearGoRuntimeBaseFromPATH() {
374+
if (terminalCreationListener) {
375+
const l = terminalCreationListener;
376+
terminalCreationListener = undefined;
377+
l.dispose();
378+
}
379+
const pathEnvVar = pathEnvVarName();
380+
if (!pathEnvVar) {
381+
logVerbose(`couldn't find PATH property in process.env`);
382+
return;
383+
}
384+
environmentVariableCollection?.delete(pathEnvVar);
385+
}
386+
362387
/**
363388
* update the PATH variable in the given terminal to default to the currently selected Go
364389
*/
365390
export async function updateIntegratedTerminal(terminal: vscode.Terminal): Promise<void> {
366391
if (!terminal) { return; }
367392
const gorootBin = path.join(getCurrentGoRoot(), 'bin');
368-
const defaultGoRuntimeBin = path.dirname(getBinPathFromEnvVar('go', defaultPathEnv, false));
369-
if (gorootBin === defaultGoRuntimeBin) {
393+
const defaultGoRuntime = getBinPathFromEnvVar('go', defaultPathEnv, false);
394+
if (defaultGoRuntime && gorootBin === path.dirname(defaultGoRuntime)) {
370395
return;
371396
}
372397

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 { logVerbose } from './goLogging';
1818
import { restartLanguageServer } from './goMain';
@@ -392,6 +392,9 @@ export function updateGoVarsFromConfig(): Promise<void> {
392392
// version of go than the system default found from PATH (or Path).
393393
if (why !== 'path') {
394394
addGoRuntimeBaseToPATH(path.join(getCurrentGoRoot(), 'bin'));
395+
} else {
396+
// clear pre-existing terminal PATH mutation logic set up by this extension.
397+
clearGoRuntimeBaseFromPATH();
395398
}
396399
initGoStatusBar();
397400
// 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
@@ -19,7 +19,8 @@ let binPathCache: { [bin: string]: string } = {};
1919

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

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

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

6768
const binname = alternateTool && !path.isAbsolute(alternateTool) ? alternateTool : toolName;
69+
const found = (why: string) => binname === toolName ? why : 'alternateTool';
6870
const pathFromGoBin = getBinPathFromEnvVar(binname, process.env['GOBIN'], false);
6971
if (pathFromGoBin) {
7072
binPathCache[toolName] = pathFromGoBin;
71-
return {binPath: pathFromGoBin, why: 'gobin'};
73+
return {binPath: pathFromGoBin, why: binname === toolName ? 'gobin' : 'alternateTool'};
7274
}
7375

7476
for (const preferred of preferredGopaths) {
@@ -77,7 +79,7 @@ export function getBinPathWithPreferredGopathGorootWithExplanation(
7779
const pathFrompreferredGoPath = getBinPathFromEnvVar(binname, preferred, true);
7880
if (pathFrompreferredGoPath) {
7981
binPathCache[toolName] = pathFrompreferredGoPath;
80-
return {binPath: pathFrompreferredGoPath, why: 'gopath'};
82+
return {binPath: pathFrompreferredGoPath, why: found('gopath')};
8183
}
8284
}
8385
}
@@ -86,14 +88,14 @@ export function getBinPathWithPreferredGopathGorootWithExplanation(
8688
const pathFromGoRoot = getBinPathFromEnvVar(binname, preferredGoroot || getCurrentGoRoot(), true);
8789
if (pathFromGoRoot) {
8890
binPathCache[toolName] = pathFromGoRoot;
89-
return {binPath: pathFromGoRoot, why: 'goroot'};
91+
return {binPath: pathFromGoRoot, why: found('goroot')};
9092
}
9193

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

99101
// Check default path for go

0 commit comments

Comments
 (0)