diff --git a/src/client/interpreter/activation/service.ts b/src/client/interpreter/activation/service.ts index 24007581daf5..baa05656853a 100644 --- a/src/client/interpreter/activation/service.ts +++ b/src/client/interpreter/activation/service.ts @@ -16,7 +16,7 @@ import { sleep } from '../../common/utils/async'; import { InMemoryCache } from '../../common/utils/cacheUtils'; import { OSType } from '../../common/utils/platform'; import { IEnvironmentVariablesProvider } from '../../common/variables/types'; -import { EnvironmentType, PythonEnvironment } from '../../pythonEnvironments/info'; +import { PythonEnvironment } from '../../pythonEnvironments/info'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; import { IInterpreterService } from '../contracts'; @@ -30,7 +30,6 @@ import { traceVerbose, traceWarn, } from '../../logging'; -import { Conda } from '../../pythonEnvironments/common/environmentManagers/conda'; const ENVIRONMENT_PREFIX = 'e8b39361-0157-4923-80e1-22d70d46dee6'; const CACHE_DURATION = 10 * 60 * 1000; @@ -170,41 +169,20 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi if (!shellInfo) { return; } + let isPossiblyCondaEnv = false; try { - let command: string | undefined; - let [args, parse] = internalScripts.printEnvVariables(); - args.forEach((arg, i) => { - args[i] = arg.toCommandArgumentForPythonExt(); - }); - interpreter = interpreter ?? (await this.interpreterService.getActiveInterpreter(resource)); - if (interpreter?.envType === EnvironmentType.Conda) { - const conda = await Conda.getConda(); - const pythonArgv = await conda?.getRunPythonArgs({ - name: interpreter.envName, - prefix: interpreter.envPath ?? '', - }); - if (pythonArgv) { - // Using environment prefix isn't needed as the marker script already takes care of it. - command = [...pythonArgv, ...args].map((arg) => arg.toCommandArgumentForPythonExt()).join(' '); - } - } - if (!command) { - 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; - } - // Run the activate command collect the environment from it. - const activationCommand = this.fixActivationCommands(activationCommands).join(' && '); - // In order to make sure we know where the environment output is, - // put in a dummy echo we can look for - command = `${activationCommand} && echo '${ENVIRONMENT_PREFIX}' && python ${args.join(' ')}`; + 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; } - + isPossiblyCondaEnv = activationCommands.join(' ').toLowerCase().includes('conda'); + // Run the activate command collect the environment from it. + const activationCommand = this.fixActivationCommands(activationCommands).join(' && '); const processService = await this.processServiceFactory.create(resource); const customEnvVars = await this.envVarsService.getEnvironmentVariables(resource); const hasCustomEnvVars = Object.keys(customEnvVars).length; @@ -216,6 +194,14 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi env[PYTHON_WARNINGS] = 'ignore'; traceVerbose(`${hasCustomEnvVars ? 'Has' : 'No'} Custom Env Vars`); + + // In order to make sure we know where the environment output is, + // put in a dummy echo we can look for + const [args, parse] = internalScripts.printEnvVariables(); + args.forEach((arg, i) => { + args[i] = arg.toCommandArgumentForPythonExt(); + }); + const command = `${activationCommand} && echo '${ENVIRONMENT_PREFIX}' && python ${args.join(' ')}`; traceVerbose(`Activating Environment to capture Environment variables, ${command}`); // Do some wrapping of the call. For two reasons: @@ -233,10 +219,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi result = await processService.shellExec(command, { env, shell: shellInfo.shell, - timeout: - interpreter?.envType === EnvironmentType.Conda - ? CONDA_ENVIRONMENT_TIMEOUT - : ENVIRONMENT_TIMEOUT, + timeout: isPossiblyCondaEnv ? CONDA_ENVIRONMENT_TIMEOUT : ENVIRONMENT_TIMEOUT, maxBuffer: 1000 * 1000, throwOnStdErr: false, }); @@ -282,7 +265,7 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi } catch (e) { traceError('getActivatedEnvironmentVariables', e); sendTelemetryEvent(EventName.ACTIVATE_ENV_TO_GET_ENV_VARS_FAILED, undefined, { - isPossiblyCondaEnv: interpreter?.envType === EnvironmentType.Conda, + isPossiblyCondaEnv, terminal: shellInfo.shellType, }); @@ -300,9 +283,6 @@ export class EnvironmentActivationService implements IEnvironmentActivationServi @traceDecoratorError('Failed to parse Environment variables') @traceDecoratorVerbose('parseEnvironmentOutput', TraceOptions.None) protected parseEnvironmentOutput(output: string, parse: (out: string) => NodeJS.ProcessEnv | undefined) { - if (output.indexOf(ENVIRONMENT_PREFIX) === -1) { - return parse(output); - } output = output.substring(output.indexOf(ENVIRONMENT_PREFIX) + ENVIRONMENT_PREFIX.length); const js = output.substring(output.indexOf('{')).trim(); return parse(js); diff --git a/src/test/interpreters/activation/service.unit.test.ts b/src/test/interpreters/activation/service.unit.test.ts index d50b2b5d5995..9e705f247ac9 100644 --- a/src/test/interpreters/activation/service.unit.test.ts +++ b/src/test/interpreters/activation/service.unit.test.ts @@ -58,7 +58,7 @@ suite('Interpreters Activation - Python Environment Variables', () => { architecture: Architecture.x64, }; - function initSetup(interpreter: PythonEnvironment | undefined) { + function initSetup() { helper = mock(TerminalHelper); platform = mock(PlatformService); processServiceFactory = mock(ProcessServiceFactory); @@ -71,7 +71,6 @@ suite('Interpreters Activation - Python Environment Variables', () => { onDidChangeInterpreter = new EventEmitter<void>(); when(envVarsService.onDidEnvironmentVariablesChange).thenReturn(onDidChangeEnvVariables.event); when(interpreterService.onDidChangeInterpreter).thenReturn(onDidChangeInterpreter.event); - when(interpreterService.getActiveInterpreter(anything())).thenResolve(interpreter); service = new EnvironmentActivationService( instance(helper), instance(platform), @@ -90,7 +89,7 @@ suite('Interpreters Activation - Python Environment Variables', () => { [undefined, Uri.parse('a')].forEach((resource) => [undefined, pythonInterpreter].forEach((interpreter) => { suite(title(resource, interpreter), () => { - setup(() => initSetup(interpreter)); + setup(initSetup); test('Unknown os will return empty variables', async () => { when(platform.osType).thenReturn(OSType.Unknown); const env = await service.getActivatedEnvironmentVariables(resource); @@ -103,7 +102,7 @@ suite('Interpreters Activation - Python Environment Variables', () => { osTypes.forEach((osType) => { suite(osType.name, () => { - setup(() => initSetup(interpreter)); + setup(initSetup); test('getEnvironmentActivationShellCommands will be invoked', async () => { when(platform.osType).thenReturn(osType.value); when(