Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/2 Fixes/5929.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixes to activation of Conda environments
8 changes: 2 additions & 6 deletions src/client/common/terminal/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,8 @@ export class TerminalHelper implements ITerminalHelper {
this.sendTelemetry(resource, terminalShellType, EventName.PYTHON_INTERPRETER_ACTIVATION_FOR_TERMINAL, promise).ignoreErrors();
return promise;
}
public async getEnvironmentActivationShellCommands(resource: Resource, interpreter?: PythonInterpreter): Promise<string[] | undefined> {
if (this.platform.osType === OSType.Unknown){
return;
}
const shell = this.shellDetector.identifyTerminalShell();
if (!shell) {
public async getEnvironmentActivationShellCommands(resource: Resource, shell: TerminalShellType, interpreter?: PythonInterpreter): Promise<string[] | undefined> {
if (this.platform.osType === OSType.Unknown) {
return;
}
const providers = [this.bashCShellFish, this.commandPromptAndPowerShell];
Expand Down
2 changes: 1 addition & 1 deletion src/client/common/terminal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export interface ITerminalHelper {
identifyTerminalShell(terminal?: Terminal): TerminalShellType;
buildCommandForTerminal(terminalShellType: TerminalShellType, command: string, args: string[]): string;
getEnvironmentActivationCommands(terminalShellType: TerminalShellType, resource?: Uri): Promise<string[] | undefined>;
getEnvironmentActivationShellCommands(resource: Resource, interpreter?: PythonInterpreter): Promise<string[] | undefined>;
getEnvironmentActivationShellCommands(resource: Resource, shell: TerminalShellType, interpreter?: PythonInterpreter): Promise<string[] | undefined>;
}

export const ITerminalActivator = Symbol('ITerminalActivator');
Expand Down
18 changes: 9 additions & 9 deletions src/client/interpreter/activation/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as path from 'path';
import { LogOptions, traceDecorators, traceError, traceVerbose } from '../../common/logger';
import { IPlatformService } from '../../common/platform/types';
import { IProcessServiceFactory } from '../../common/process/types';
import { ITerminalHelper } from '../../common/terminal/types';
import { ITerminalHelper, TerminalShellType } from '../../common/terminal/types';
import { ICurrentProcess, IDisposable, Resource } from '../../common/types';
import {
cacheResourceSpecificInterpreterData,
Expand All @@ -29,9 +29,9 @@ const getEnvironmentTimeout = 30000;

// The shell under which we'll execute activation scripts.
const defaultShells = {
[OSType.Windows]: 'cmd',
[OSType.OSX]: 'bash',
[OSType.Linux]: 'bash',
[OSType.Windows]: { shell: 'cmd', shellType: TerminalShellType.commandPrompt },
[OSType.OSX]: { shell: 'bash', shellType: TerminalShellType.bash },
[OSType.Linux]: { shell: 'bash', shellType: TerminalShellType.bash },
[OSType.Unknown]: undefined
};

Expand All @@ -54,14 +54,14 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi
@captureTelemetry(EventName.PYTHON_INTERPRETER_ACTIVATION_ENVIRONMENT_VARIABLES, { failed: false }, true)
@cacheResourceSpecificInterpreterData('ActivatedEnvironmentVariables', cacheDuration)
public async getActivatedEnvironmentVariables(resource: Resource, interpreter?: PythonInterpreter, allowExceptions?: boolean): Promise<NodeJS.ProcessEnv | undefined> {
const shell = defaultShells[this.platform.osType];
if (!shell) {
const shellInfo = defaultShells[this.platform.osType];
if (!shellInfo) {
return;
}

try {
const activationCommands = await this.helper.getEnvironmentActivationShellCommands(resource, interpreter);
traceVerbose(`Activation Commands received ${activationCommands}`);
const activationCommands = await this.helper.getEnvironmentActivationShellCommands(resource, shellInfo.shellType, interpreter);
traceVerbose(`Activation Commands received ${activationCommands} for shell ${shellInfo.shell}`);
if (!activationCommands || !Array.isArray(activationCommands) || activationCommands.length === 0) {
return;
}
Expand All @@ -84,7 +84,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi
// See the discussion from hidesoon in this issue: https://github.com/Microsoft/vscode-python/issues/4424
// His issue is conda never finishing during activate. This is a conda issue, but we
// should at least tell the user.
const result = await processService.shellExec(command, { env, shell, timeout: getEnvironmentTimeout, maxBuffer: 1000 * 1000 });
const result = await processService.shellExec(command, { env, shell: shellInfo.shell, timeout: getEnvironmentTimeout, maxBuffer: 1000 * 1000 });
if (result.stderr && result.stderr.length > 0) {
throw new Error(`StdErr from ShellExec, ${result.stderr}`);
}
Expand Down
9 changes: 5 additions & 4 deletions src/test/common/terminals/helper.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,10 @@ suite('Terminal Service helpers', () => {
test('Activation command for Shell must be empty for unknown os', async () => {
when(platformService.osType).thenReturn(OSType.Unknown);

const cmd = await helper.getEnvironmentActivationShellCommands(resource, interpreter);

expect(cmd).to.equal(undefined, 'Command must be undefined');
for (const item of getNamesAndValues<TerminalShellType>(TerminalShellType)) {
const cmd = await helper.getEnvironmentActivationShellCommands(resource, item.value, interpreter);
expect(cmd).to.equal(undefined, 'Command must be undefined');
}
});
});
[undefined, pythonInterpreter].forEach(interpreter => {
Expand All @@ -332,7 +333,7 @@ suite('Terminal Service helpers', () => {
when(bashActivationProvider.isShellSupported(shellToExpect)).thenReturn(false);
when(cmdActivationProvider.isShellSupported(shellToExpect)).thenReturn(false);

const cmd = await helper.getEnvironmentActivationShellCommands(resource, interpreter);
const cmd = await helper.getEnvironmentActivationShellCommands(resource, shellToExpect, interpreter);

expect(cmd).to.equal(undefined, 'Command must be undefined');
verify(pythonSettings.terminal).once();
Expand Down
25 changes: 12 additions & 13 deletions src/test/interpreters/activation/service.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { SemVer } from 'semver';
import { anything, capture, instance, mock, verify, when } from 'ts-mockito';
import * as typemoq from 'typemoq';
import { Uri, workspace as workspaceType, WorkspaceConfiguration } from 'vscode';

import { PlatformService } from '../../../client/common/platform/platformService';
import { IPlatformService } from '../../../client/common/platform/types';
import { CurrentProcess } from '../../../client/common/process/currentProcess';
Expand Down Expand Up @@ -111,27 +110,27 @@ suite('Interprters Activation - Python Environment Variables', () => {
setup(initSetup);
test('getEnvironmentActivationShellCommands will be invoked', async () => {
when(platform.osType).thenReturn(osType.value);
when(helper.getEnvironmentActivationShellCommands(resource, interpreter)).thenResolve();
when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve();

const env = await service.getActivatedEnvironmentVariables(resource, interpreter);

verify(platform.osType).once();
expect(env).to.equal(undefined, 'Should not have any variables');
verify(helper.getEnvironmentActivationShellCommands(resource, interpreter)).once();
verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).once();
});
test('Validate command used to activation and printing env vars', async () => {
const cmd = ['1', '2'];
const envVars = { one: '1', two: '2' };
when(platform.osType).thenReturn(osType.value);
when(helper.getEnvironmentActivationShellCommands(resource, interpreter)).thenResolve(cmd);
when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve(cmd);
when(processServiceFactory.create(resource)).thenResolve(instance(processService));
when(envVarsService.getEnvironmentVariables(resource)).thenResolve(envVars);

const env = await service.getActivatedEnvironmentVariables(resource, interpreter);

verify(platform.osType).once();
expect(env).to.equal(undefined, 'Should not have any variables');
verify(helper.getEnvironmentActivationShellCommands(resource, interpreter)).once();
verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).once();
verify(processServiceFactory.create(resource)).once();
verify(envVarsService.getEnvironmentVariables(resource)).once();
verify(processService.shellExec(anything(), anything())).once();
Expand All @@ -147,15 +146,15 @@ suite('Interprters Activation - Python Environment Variables', () => {
const cmd = ['1', '2'];
const envVars = { one: '1', two: '2' };
when(platform.osType).thenReturn(osType.value);
when(helper.getEnvironmentActivationShellCommands(resource, interpreter)).thenResolve(cmd);
when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve(cmd);
when(processServiceFactory.create(resource)).thenResolve(instance(processService));
when(envVarsService.getEnvironmentVariables(resource)).thenResolve(envVars);

const env = await service.getActivatedEnvironmentVariables(resource, interpreter);

verify(platform.osType).once();
expect(env).to.equal(undefined, 'Should not have any variables');
verify(helper.getEnvironmentActivationShellCommands(resource, interpreter)).once();
verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).once();
verify(processServiceFactory.create(resource)).once();
verify(envVarsService.getEnvironmentVariables(resource)).once();
verify(processService.shellExec(anything(), anything())).once();
Expand All @@ -169,7 +168,7 @@ suite('Interprters Activation - Python Environment Variables', () => {
const cmd = ['1', '2'];
const envVars = { one: '1', two: '2' };
when(platform.osType).thenReturn(osType.value);
when(helper.getEnvironmentActivationShellCommands(resource, interpreter)).thenResolve(cmd);
when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve(cmd);
when(processServiceFactory.create(resource)).thenResolve(instance(processService));
when(envVarsService.getEnvironmentVariables(resource)).thenResolve({});
when(currentProcess.env).thenReturn(envVars);
Expand All @@ -178,7 +177,7 @@ suite('Interprters Activation - Python Environment Variables', () => {

verify(platform.osType).once();
expect(env).to.equal(undefined, 'Should not have any variables');
verify(helper.getEnvironmentActivationShellCommands(resource, interpreter)).once();
verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).once();
verify(processServiceFactory.create(resource)).once();
verify(envVarsService.getEnvironmentVariables(resource)).once();
verify(processService.shellExec(anything(), anything())).once();
Expand All @@ -193,7 +192,7 @@ suite('Interprters Activation - Python Environment Variables', () => {
const cmd = ['1', '2'];
const envVars = { one: '1', two: '2' };
when(platform.osType).thenReturn(osType.value);
when(helper.getEnvironmentActivationShellCommands(resource, interpreter)).thenResolve(cmd);
when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve(cmd);
when(processServiceFactory.create(resource)).thenResolve(instance(processService));
when(envVarsService.getEnvironmentVariables(resource)).thenResolve(envVars);
when(processService.shellExec(anything(), anything())).thenReject(new Error('kaboom'));
Expand All @@ -202,7 +201,7 @@ suite('Interprters Activation - Python Environment Variables', () => {

verify(platform.osType).once();
expect(env).to.equal(undefined, 'Should not have any variables');
verify(helper.getEnvironmentActivationShellCommands(resource, interpreter)).once();
verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).once();
verify(processServiceFactory.create(resource)).once();
verify(envVarsService.getEnvironmentVariables(resource)).once();
verify(processService.shellExec(anything(), anything())).once();
Expand All @@ -213,7 +212,7 @@ suite('Interprters Activation - Python Environment Variables', () => {
const varsFromEnv = { one: '11', two: '22', HELLO: 'xxx' };
const stdout = `${getEnvironmentPrefix}${EOL}${JSON.stringify(varsFromEnv)}`;
when(platform.osType).thenReturn(osType.value);
when(helper.getEnvironmentActivationShellCommands(resource, interpreter)).thenResolve(cmd);
when(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).thenResolve(cmd);
when(processServiceFactory.create(resource)).thenResolve(instance(processService));
when(envVarsService.getEnvironmentVariables(resource)).thenResolve(envVars);
when(processService.shellExec(anything(), anything())).thenResolve({ stdout: stdout });
Expand All @@ -222,7 +221,7 @@ suite('Interprters Activation - Python Environment Variables', () => {

verify(platform.osType).once();
expect(env).to.deep.equal(varsFromEnv);
verify(helper.getEnvironmentActivationShellCommands(resource, interpreter)).once();
verify(helper.getEnvironmentActivationShellCommands(resource, anything(), interpreter)).once();
verify(processServiceFactory.create(resource)).once();
verify(envVarsService.getEnvironmentVariables(resource)).once();
verify(processService.shellExec(anything(), anything())).once();
Expand Down