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
5 changes: 0 additions & 5 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,8 @@ src/test/common/crypto.unit.test.ts
src/test/common/configuration/service.unit.test.ts
src/test/common/net/fileDownloader.unit.test.ts
src/test/common/net/httpClient.unit.test.ts
src/test/common/moduleInstaller.test.ts
src/test/common/terminals/activator/index.unit.test.ts
src/test/common/terminals/activator/base.unit.test.ts
src/test/common/terminals/activation.conda.unit.test.ts
src/test/common/terminals/shellDetector.unit.test.ts
src/test/common/terminals/service.unit.test.ts
src/test/common/terminals/helper.unit.test.ts
Expand Down Expand Up @@ -222,7 +220,6 @@ src/test/common/installer/channelManager.unit.test.ts
src/test/common/installer/installer.unit.test.ts
src/test/common/installer/pipInstaller.unit.test.ts
src/test/common/installer/installer.invalidPath.unit.test.ts
src/test/common/installer/moduleInstaller.unit.test.ts
src/test/common/installer/pipEnvInstaller.unit.test.ts
src/test/common/installer/productPath.unit.test.ts
src/test/common/installer/extensionBuildInstaller.unit.test.ts
Expand Down Expand Up @@ -559,7 +556,6 @@ src/client/common/terminal/shellDetectors/settingsShellDetector.ts
src/client/common/terminal/shellDetectors/baseShellDetector.ts
src/client/common/terminal/environmentActivationProviders/pipEnvActivationProvider.ts
src/client/common/terminal/environmentActivationProviders/baseActivationProvider.ts
src/client/common/terminal/environmentActivationProviders/condaActivationProvider.ts
src/client/common/terminal/environmentActivationProviders/commandPrompt.ts
src/client/common/terminal/environmentActivationProviders/bash.ts
src/client/common/terminal/environmentActivationProviders/pyenvActivationProvider.ts
Expand Down Expand Up @@ -622,7 +618,6 @@ src/client/common/application/terminalManager.ts
src/client/common/application/applicationEnvironment.ts
src/client/common/errors/errorUtils.ts
src/client/common/installer/serviceRegistry.ts
src/client/common/installer/condaInstaller.ts
src/client/common/installer/extensionBuildInstaller.ts
src/client/common/installer/productInstaller.ts
src/client/common/installer/channelManager.ts
Expand Down
21 changes: 16 additions & 5 deletions src/client/common/installer/condaInstaller.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* eslint-disable class-methods-use-this */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import { inject, injectable } from 'inversify';
import { ICondaService, ICondaLocatorService } from '../../interpreter/contracts';
import { ICondaService, ICondaLocatorService, IComponentAdapter } from '../../interpreter/contracts';
import { IServiceContainer } from '../../ioc/types';
import { ExecutionInfo, IConfigurationService } from '../types';
import { inDiscoveryExperiment } from '../experiments/helpers';
import { ExecutionInfo, IConfigurationService, IExperimentService } from '../types';
import { isResource } from '../utils/misc';
import { ModuleInstaller } from './moduleInstaller';
import { InterpreterUri } from './types';
Expand All @@ -16,6 +18,9 @@ import { InterpreterUri } from './types';
export class CondaInstaller extends ModuleInstaller {
public _isCondaAvailable: boolean | undefined;

// Unfortunately inversify requires the number of args in constructor to be explictly
// specified as more than its base class. So we need the constructor.
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) {
super(serviceContainer);
}
Expand All @@ -24,7 +29,7 @@ export class CondaInstaller extends ModuleInstaller {
return 'Conda';
}

public get displayName() {
public get displayName(): string {
return 'Conda';
}

Expand Down Expand Up @@ -67,7 +72,10 @@ export class CondaInstaller extends ModuleInstaller {
const pythonPath = isResource(resource)
? this.serviceContainer.get<IConfigurationService>(IConfigurationService).getSettings(resource).pythonPath
: resource.path;
const condaLocatorService = this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const experimentService = this.serviceContainer.get<IExperimentService>(IExperimentService);
const condaLocatorService = (await inDiscoveryExperiment(experimentService))
? this.serviceContainer.get<IComponentAdapter>(IComponentAdapter)
: this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const info = await condaLocatorService.getCondaEnvironment(pythonPath);
const args = [isUpgrade ? 'update' : 'install'];

Expand Down Expand Up @@ -97,7 +105,10 @@ export class CondaInstaller extends ModuleInstaller {
* Is the provided interprter a conda environment
*/
private async isCurrentEnvironmentACondaEnvironment(resource?: InterpreterUri): Promise<boolean> {
const condaService = this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const experimentService = this.serviceContainer.get<IExperimentService>(IExperimentService);
const condaService = (await inDiscoveryExperiment(experimentService))
? this.serviceContainer.get<IComponentAdapter>(IComponentAdapter)
: this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const pythonPath = isResource(resource)
? this.serviceContainer.get<IConfigurationService>(IConfigurationService).getSettings(resource).pythonPath
: resource.path;
Expand Down
5 changes: 4 additions & 1 deletion src/client/common/process/pythonExecutionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,12 @@ export class PythonExecutionFactory implements IPythonExecutionFactory {
const processServicePromise = processService
? Promise.resolve(processService)
: this.processServiceFactory.create(resource);
const condaLocatorService = (await inDiscoveryExperiment(this.experimentService))
? this.serviceContainer.get<IComponentAdapter>(IComponentAdapter)
: this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const [condaVersion, condaEnvironment, condaFile, procService] = await Promise.all([
this.condaService.getCondaVersion(),
this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService).getCondaEnvironment(pythonPath),
condaLocatorService.getCondaEnvironment(pythonPath),
this.condaService.getCondaFile(),
processServicePromise,
]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

'use strict';

import '../../extensions';

import { inject, injectable } from 'inversify';
import * as path from 'path';
import { Uri } from 'vscode';

import { ICondaLocatorService, ICondaService } from '../../../interpreter/contracts';
import { IComponentAdapter, ICondaLocatorService, ICondaService } from '../../../interpreter/contracts';
import { IPlatformService } from '../../platform/types';
import { IConfigurationService } from '../../types';
import { IConfigurationService, IExperimentService } from '../../types';
import { ITerminalActivationCommandProvider, TerminalShellType } from '../types';
import { IServiceContainer } from '../../../ioc/types';
import { inDiscoveryExperiment } from '../../experiments/helpers';

// Version number of conda that requires we call activate with 'conda activate' instead of just 'activate'
const CondaRequiredMajor = 4;
Expand All @@ -28,12 +31,15 @@ export class CondaActivationCommandProvider implements ITerminalActivationComman
@inject(IPlatformService) private platform: IPlatformService,
@inject(IConfigurationService) private configService: IConfigurationService,
@inject(IServiceContainer) private serviceContainer: IServiceContainer,
@inject(IExperimentService) private experimentService: IExperimentService,
@inject(IComponentAdapter) private pyenvs: IComponentAdapter,
) {}

/**
* Is the given shell supported for activating a conda env?
*/
public isShellSupported(_targetShell: TerminalShellType): boolean {
// eslint-disable-next-line class-methods-use-this
public isShellSupported(): boolean {
return true;
}

Expand All @@ -44,7 +50,7 @@ export class CondaActivationCommandProvider implements ITerminalActivationComman
resource: Uri | undefined,
targetShell: TerminalShellType,
): Promise<string[] | undefined> {
const pythonPath = this.configService.getSettings(resource).pythonPath;
const { pythonPath } = this.configService.getSettings(resource);
return this.getActivationCommandsForInterpreter(pythonPath, targetShell);
}

Expand All @@ -56,10 +62,12 @@ export class CondaActivationCommandProvider implements ITerminalActivationComman
pythonPath: string,
targetShell: TerminalShellType,
): Promise<string[] | undefined> {
const condaLocatorService = this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const condaLocatorService = (await inDiscoveryExperiment(this.experimentService))
? this.pyenvs
: this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
const envInfo = await condaLocatorService.getCondaEnvironment(pythonPath);
if (!envInfo) {
return;
return undefined;
}

const condaEnv = envInfo.name.length > 0 ? envInfo.name : envInfo.path;
Expand All @@ -75,7 +83,7 @@ export class CondaActivationCommandProvider implements ITerminalActivationComman
versionInfo.minor >= CondaRequiredMinorForPowerShell &&
(targetShell === TerminalShellType.powershell || targetShell === TerminalShellType.powershellCore)
) {
return this.getPowershellCommands(condaEnv);
return _getPowershellCommands(condaEnv);
}
if (versionInfo.minor >= CondaRequiredMinor) {
// New version.
Expand All @@ -91,23 +99,22 @@ export class CondaActivationCommandProvider implements ITerminalActivationComman
switch (targetShell) {
case TerminalShellType.powershell:
case TerminalShellType.powershellCore:
return this.getPowershellCommands(condaEnv);
return _getPowershellCommands(condaEnv);

// TODO: Do we really special-case fish on Windows?
case TerminalShellType.fish:
return this.getFishCommands(condaEnv, await this.condaService.getCondaFile());
return getFishCommands(condaEnv, await this.condaService.getCondaFile());

default:
if (this.platform.isWindows) {
return this.getWindowsCommands(condaEnv);
} else {
return this.getUnixCommands(condaEnv, await this.condaService.getCondaFile());
}
return getUnixCommands(condaEnv, await this.condaService.getCondaFile());
}
}

public async getWindowsActivateCommand(): Promise<string> {
let activateCmd: string = 'activate';
let activateCmd = 'activate';

const condaExePath = await this.condaService.getCondaFile();

Expand All @@ -125,28 +132,25 @@ export class CondaActivationCommandProvider implements ITerminalActivationComman
const activate = await this.getWindowsActivateCommand();
return [`${activate} ${condaEnv.toCommandArgument()}`];
}
/**
* The expectation is for the user to configure Powershell for Conda.
* Hence we just send the command `conda activate ...`.
* This configuration is documented on Conda.
* Extension will not attempt to work around issues by trying to setup shell for user.
*
* @param {string} condaEnv
* @returns {(Promise<string[] | undefined>)}
* @memberof CondaActivationCommandProvider
*/
public async getPowershellCommands(condaEnv: string): Promise<string[] | undefined> {
return [`conda activate ${condaEnv.toCommandArgument()}`];
}
}

public async getFishCommands(condaEnv: string, condaFile: string): Promise<string[] | undefined> {
// https://github.com/conda/conda/blob/be8c08c083f4d5e05b06bd2689d2cd0d410c2ffe/shell/etc/fish/conf.d/conda.fish#L18-L28
return [`${condaFile.fileToCommandArgument()} activate ${condaEnv.toCommandArgument()}`];
}
/**
* The expectation is for the user to configure Powershell for Conda.
* Hence we just send the command `conda activate ...`.
* This configuration is documented on Conda.
* Extension will not attempt to work around issues by trying to setup shell for user.
*/
export async function _getPowershellCommands(condaEnv: string): Promise<string[] | undefined> {
return [`conda activate ${condaEnv.toCommandArgument()}`];
}

public async getUnixCommands(condaEnv: string, condaFile: string): Promise<string[] | undefined> {
const condaDir = path.dirname(condaFile);
const activateFile = path.join(condaDir, 'activate');
return [`source ${activateFile.fileToCommandArgument()} ${condaEnv.toCommandArgument()}`];
}
async function getFishCommands(condaEnv: string, condaFile: string): Promise<string[] | undefined> {
// https://github.com/conda/conda/blob/be8c08c083f4d5e05b06bd2689d2cd0d410c2ffe/shell/etc/fish/conf.d/conda.fish#L18-L28
return [`${condaFile.fileToCommandArgument()} activate ${condaEnv.toCommandArgument()}`];
}

async function getUnixCommands(condaEnv: string, condaFile: string): Promise<string[] | undefined> {
const condaDir = path.dirname(condaFile);
const activateFile = path.join(condaDir, 'activate');
return [`source ${activateFile.fileToCommandArgument()} ${condaEnv.toCommandArgument()}`];
}
14 changes: 10 additions & 4 deletions src/client/common/terminal/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@

import { inject, injectable, multiInject, named } from 'inversify';
import { Terminal, Uri } from 'vscode';
import { ICondaLocatorService, IInterpreterService } from '../../interpreter/contracts';
import { IComponentAdapter, ICondaLocatorService, IInterpreterService } from '../../interpreter/contracts';
import { IServiceContainer } from '../../ioc/types';
import { EnvironmentType, PythonEnvironment } from '../../pythonEnvironments/info';
import { sendTelemetryEvent } from '../../telemetry';
import { EventName } from '../../telemetry/constants';
import { ITerminalManager } from '../application/types';
import { inDiscoveryExperiment } from '../experiments/helpers';
import '../extensions';
import { traceDecorators, traceError } from '../logger';
import { IPlatformService } from '../platform/types';
import { IConfigurationService, Resource } from '../types';
import { IConfigurationService, IExperimentService, Resource } from '../types';
import { OSType } from '../utils/platform';
import { ShellDetector } from './shellDetector';
import {
Expand All @@ -28,7 +30,7 @@ export class TerminalHelper implements ITerminalHelper {
constructor(
@inject(IPlatformService) private readonly platform: IPlatformService,
@inject(ITerminalManager) private readonly terminalManager: ITerminalManager,
@inject(ICondaLocatorService) private readonly condaService: ICondaLocatorService,
@inject(IServiceContainer) private readonly serviceContainer: IServiceContainer,
@inject(IInterpreterService) readonly interpreterService: IInterpreterService,
@inject(IConfigurationService) private readonly configurationService: IConfigurationService,
@inject(ITerminalActivationCommandProvider)
Expand Down Expand Up @@ -129,10 +131,14 @@ export class TerminalHelper implements ITerminalHelper {
): Promise<string[] | undefined> {
const settings = this.configurationService.getSettings(resource);

const experimentService = this.serviceContainer.get<IExperimentService>(IExperimentService);
const condaService = (await inDiscoveryExperiment(experimentService))
? this.serviceContainer.get<IComponentAdapter>(IComponentAdapter)
: this.serviceContainer.get<ICondaLocatorService>(ICondaLocatorService);
// If we have a conda environment, then use that.
const isCondaEnvironment = interpreter
? interpreter.envType === EnvironmentType.Conda
: await this.condaService.isCondaEnvironment(settings.pythonPath);
: await condaService.isCondaEnvironment(settings.pythonPath);
if (isCondaEnvironment) {
const activationCommands = interpreter
? await this.conda.getActivationCommandsForInterpreter(interpreter.path, terminalShellType)
Expand Down
Loading