Skip to content

Commit f52049d

Browse files
committed
Ensure microvenv is added to path after selection.
1 parent 60db593 commit f52049d

File tree

4 files changed

+95
-18
lines changed

4 files changed

+95
-18
lines changed

src/client/interpreter/activation/service.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import '../../common/extensions';
88

9+
import * as path from 'path';
910
import { inject, injectable } from 'inversify';
1011

1112
import { IWorkspaceService } from '../../common/application/types';
@@ -25,10 +26,18 @@ import { EventName } from '../../telemetry/constants';
2526
import { IInterpreterService } from '../contracts';
2627
import { IEnvironmentActivationService } from './types';
2728
import { TraceOptions } from '../../logging/types';
28-
import { traceDecoratorError, traceDecoratorVerbose, traceError, traceVerbose, traceWarn } from '../../logging';
29+
import {
30+
traceDecoratorError,
31+
traceDecoratorVerbose,
32+
traceError,
33+
traceInfo,
34+
traceVerbose,
35+
traceWarn,
36+
} from '../../logging';
2937
import { Conda } from '../../pythonEnvironments/common/environmentManagers/conda';
3038
import { StopWatch } from '../../common/utils/stopWatch';
3139
import { identifyShellFromShellPath } from '../../common/terminal/shellDetectors/baseShellDetector';
40+
import { getSearchPathEnvVarNames } from '../../common/utils/exec';
3241

3342
const ENVIRONMENT_PREFIX = 'e8b39361-0157-4923-80e1-22d70d46dee6';
3443
const CACHE_DURATION = 10 * 60 * 1000;
@@ -193,6 +202,11 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi
193202
shellInfo = { shellType: customShellType, shell };
194203
}
195204
try {
205+
const processService = await this.processServiceFactory.create(resource);
206+
const customEnvVars = (await this.envVarsService.getEnvironmentVariables(resource)) ?? {};
207+
const hasCustomEnvVars = Object.keys(customEnvVars).length;
208+
const env = hasCustomEnvVars ? customEnvVars : { ...this.currentProcess.env };
209+
196210
let command: string | undefined;
197211
const [args, parse] = internalScripts.printEnvVariables();
198212
args.forEach((arg, i) => {
@@ -217,6 +231,16 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi
217231
);
218232
traceVerbose(`Activation Commands received ${activationCommands} for shell ${shellInfo.shell}`);
219233
if (!activationCommands || !Array.isArray(activationCommands) || activationCommands.length === 0) {
234+
if (interpreter?.envType === EnvironmentType.Venv) {
235+
const key = getSearchPathEnvVarNames()[0];
236+
if (env[key]) {
237+
env[key] = `${path.dirname(interpreter.path)}${path.delimiter}${env[key]}`;
238+
} else {
239+
env[key] = `${path.dirname(interpreter.path)}`;
240+
}
241+
242+
return env;
243+
}
220244
return undefined;
221245
}
222246
// Run the activate command collect the environment from it.
@@ -226,11 +250,6 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi
226250
command = `${activationCommand} && echo '${ENVIRONMENT_PREFIX}' && python ${args.join(' ')}`;
227251
}
228252

229-
const processService = await this.processServiceFactory.create(resource);
230-
const customEnvVars = await this.envVarsService.getEnvironmentVariables(resource);
231-
const hasCustomEnvVars = Object.keys(customEnvVars).length;
232-
const env = hasCustomEnvVars ? customEnvVars : { ...this.currentProcess.env };
233-
234253
// Make sure python warnings don't interfere with getting the environment. However
235254
// respect the warning in the returned values
236255
const oldWarnings = env[PYTHON_WARNINGS];
@@ -283,7 +302,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi
283302
// that's the case, wait and try again. This happens especially on AzDo
284303
const excString = (exc as Error).toString();
285304
if (condaRetryMessages.find((m) => excString.includes(m)) && tryCount < 10) {
286-
traceVerbose(`Conda is busy, attempting to retry ...`);
305+
traceInfo(`Conda is busy, attempting to retry ...`);
287306
result = undefined;
288307
tryCount += 1;
289308
await sleep(500);

src/client/interpreter/activation/terminalEnvVarCollectionService.ts

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4+
import * as path from 'path';
45
import { inject, injectable } from 'inversify';
5-
import { ProgressOptions, ProgressLocation, MarkdownString } from 'vscode';
6+
import { ProgressOptions, ProgressLocation, MarkdownString, WorkspaceFolder } from 'vscode';
7+
import { pathExists } from 'fs-extra';
68
import { IExtensionActivationService } from '../../activation/types';
79
import { IApplicationShell, IApplicationEnvironment, IWorkspaceService } from '../../common/application/types';
810
import { inTerminalEnvVarExperiment } from '../../common/experiments/helpers';
@@ -22,6 +24,7 @@ import { traceDecoratorVerbose, traceVerbose } from '../../logging';
2224
import { IInterpreterService } from '../contracts';
2325
import { defaultShells } from './service';
2426
import { IEnvironmentActivationService } from './types';
27+
import { EnvironmentType } from '../../pythonEnvironments/info';
2528

2629
@injectable()
2730
export class TerminalEnvVarCollectionService implements IExtensionActivationService {
@@ -53,6 +56,17 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
5356
public async activate(resource: Resource): Promise<void> {
5457
if (!inTerminalEnvVarExperiment(this.experimentService)) {
5558
this.context.environmentVariableCollection.clear();
59+
await this.handleMicroVenv(resource);
60+
if (!this.registeredOnce) {
61+
this.interpreterService.onDidChangeInterpreter(
62+
async (r) => {
63+
await this.handleMicroVenv(r);
64+
},
65+
this,
66+
this.disposables,
67+
);
68+
this.registeredOnce = true;
69+
}
5670
return;
5771
}
5872
if (!this.registeredOnce) {
@@ -82,14 +96,7 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
8296
}
8397

8498
public async _applyCollection(resource: Resource, shell = this.applicationEnvironment.shell): Promise<void> {
85-
let workspaceFolder = this.workspaceService.getWorkspaceFolder(resource);
86-
if (
87-
!workspaceFolder &&
88-
Array.isArray(this.workspaceService.workspaceFolders) &&
89-
this.workspaceService.workspaceFolders.length > 0
90-
) {
91-
[workspaceFolder] = this.workspaceService.workspaceFolders;
92-
}
99+
const workspaceFolder = this.getWorkspaceFolder(resource);
93100
const settings = this.configurationService.getSettings(resource);
94101
if (!settings.terminal.activateEnvironment) {
95102
traceVerbose('Activating environments in terminal is disabled for', resource?.fsPath);
@@ -143,6 +150,37 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ
143150
});
144151
}
145152

153+
private async handleMicroVenv(resource: Resource) {
154+
const workspaceFolder = this.getWorkspaceFolder(resource);
155+
const interpreter = await this.interpreterService.getActiveInterpreter(resource);
156+
if (interpreter?.envType === EnvironmentType.Venv) {
157+
const activatePath = path.join(path.dirname(interpreter.path), 'activate');
158+
if (!(await pathExists(activatePath))) {
159+
this.context.environmentVariableCollection.replace(
160+
'PATH',
161+
`${path.dirname(interpreter.path)}${path.delimiter}${process.env.Path}`,
162+
{
163+
workspaceFolder,
164+
},
165+
);
166+
return;
167+
}
168+
}
169+
this.context.environmentVariableCollection.clear();
170+
}
171+
172+
private getWorkspaceFolder(resource: Resource): WorkspaceFolder | undefined {
173+
let workspaceFolder = this.workspaceService.getWorkspaceFolder(resource);
174+
if (
175+
!workspaceFolder &&
176+
Array.isArray(this.workspaceService.workspaceFolders) &&
177+
this.workspaceService.workspaceFolders.length > 0
178+
) {
179+
[workspaceFolder] = this.workspaceService.workspaceFolders;
180+
}
181+
return workspaceFolder;
182+
}
183+
146184
@traceDecoratorVerbose('Display activating terminals')
147185
private showProgress(): void {
148186
if (!this.deferred) {

src/test/interpreters/activation/service.unit.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { EnvironmentActivationService } from '../../../client/interpreter/activa
2828
import { IInterpreterService } from '../../../client/interpreter/contracts';
2929
import { InterpreterService } from '../../../client/interpreter/interpreterService';
3030
import { EnvironmentType, PythonEnvironment } from '../../../client/pythonEnvironments/info';
31+
import { getSearchPathEnvVarNames } from '../../../client/common/utils/exec';
3132

3233
const getEnvironmentPrefix = 'e8b39361-0157-4923-80e1-22d70d46dee6';
3334
const defaultShells = {
@@ -118,6 +119,25 @@ suite('Interpreters Activation - Python Environment Variables', () => {
118119
helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter),
119120
).once();
120121
});
122+
test('Env variables returned for microvenv', async () => {
123+
when(platform.osType).thenReturn(osType.value);
124+
125+
const microVenv = { ...pythonInterpreter, envType: EnvironmentType.Venv };
126+
const key = getSearchPathEnvVarNames()[0];
127+
const varsFromEnv = { [key]: '/foo/bar' };
128+
129+
when(
130+
helper.getEnvironmentActivationShellCommands(resource, anything(), microVenv),
131+
).thenResolve();
132+
133+
const env = await service.getActivatedEnvironmentVariables(resource, microVenv);
134+
135+
verify(platform.osType).once();
136+
expect(env).to.deep.equal(varsFromEnv);
137+
verify(
138+
helper.getEnvironmentActivationShellCommands(resource, anything(), microVenv),
139+
).once();
140+
});
121141
test('Validate command used to activation and printing env vars', async () => {
122142
const cmd = ['1', '2'];
123143
const envVars = { one: '1', two: '2' };

src/test/interpreters/activation/terminalEnvVarCollectionService.unit.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ suite('Terminal Environment Variable Collection Service', () => {
117117

118118
await terminalEnvVarCollectionService.activate(undefined);
119119

120-
verify(interpreterService.onDidChangeInterpreter(anything(), anything(), anything())).never();
120+
verify(interpreterService.onDidChangeInterpreter(anything(), anything(), anything())).once();
121121
verify(applicationEnvironment.onDidChangeShell(anything(), anything(), anything())).never();
122122
assert(applyCollectionStub.notCalled, 'Collection should not be applied on activation');
123123

124-
verify(collection.clear()).once();
124+
verify(collection.clear()).atLeast(1);
125125
});
126126

127127
test('When interpreter changes, apply new activated variables to the collection', async () => {

0 commit comments

Comments
 (0)