forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathcondaActivationProvider.ts
150 lines (131 loc) · 6.27 KB
/
condaActivationProvider.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 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 { ICondaService } from '../../../interpreter/contracts';
import { IPlatformService } from '../../platform/types';
import { IConfigurationService } from '../../types';
import { ITerminalActivationCommandProvider, TerminalShellType } from '../types';
// Version number of conda that requires we call activate with 'conda activate' instead of just 'activate'
const CondaRequiredMajor = 4;
const CondaRequiredMinor = 4;
const CondaRequiredMinorForPowerShell = 6;
/**
* Support conda env activation (in the terminal).
*/
@injectable()
export class CondaActivationCommandProvider implements ITerminalActivationCommandProvider {
constructor(
@inject(ICondaService) private readonly condaService: ICondaService,
@inject(IPlatformService) private platform: IPlatformService,
@inject(IConfigurationService) private configService: IConfigurationService
) {}
/**
* Is the given shell supported for activating a conda env?
*/
public isShellSupported(_targetShell: TerminalShellType): boolean {
return true;
}
/**
* Return the command needed to activate the conda env.
*/
public getActivationCommands(
resource: Uri | undefined,
targetShell: TerminalShellType
): Promise<string[] | undefined> {
const pythonPath = this.configService.getSettings(resource).pythonPath;
return this.getActivationCommandsForInterpreter(pythonPath, targetShell);
}
/**
* Return the command needed to activate the conda env.
*
*/
public async getActivationCommandsForInterpreter(
pythonPath: string,
targetShell: TerminalShellType
): Promise<string[] | undefined> {
const envInfo = await this.condaService.getCondaEnvironment(pythonPath);
if (!envInfo) {
return;
}
const condaEnv = envInfo.name.length > 0 ? envInfo.name : envInfo.path;
// Algorithm differs based on version
// Old version, just call activate directly.
// New version, call activate from the same path as our python path, then call it again to activate our environment.
// -- note that the 'default' conda location won't allow activate to work for the environment sometimes.
const versionInfo = await this.condaService.getCondaVersion();
if (versionInfo && versionInfo.major >= CondaRequiredMajor) {
// Conda added support for powershell in 4.6.
if (
versionInfo.minor >= CondaRequiredMinorForPowerShell &&
(targetShell === TerminalShellType.powershell || targetShell === TerminalShellType.powershellCore)
) {
return this.getPowershellCommands(condaEnv);
}
if (versionInfo.minor >= CondaRequiredMinor) {
// New version.
const interpreterPath = await this.condaService.getCondaFileFromInterpreter(pythonPath, envInfo.name);
if (interpreterPath) {
const activatePath = path.join(path.dirname(interpreterPath), 'activate').fileToCommandArgument();
const firstActivate = this.platform.isWindows ? activatePath : `source ${activatePath}`;
return [firstActivate, `conda activate ${condaEnv.toCommandArgument()}`];
}
}
}
switch (targetShell) {
case TerminalShellType.powershell:
case TerminalShellType.powershellCore:
return this.getPowershellCommands(condaEnv);
// tslint:disable-next-line:no-suspicious-comment
// TODO: Do we really special-case fish on Windows?
case TerminalShellType.fish:
return this.getFishCommands(condaEnv, await this.condaService.getCondaFile());
default:
if (this.platform.isWindows) {
return this.getWindowsCommands(condaEnv);
} else {
return this.getUnixCommands(condaEnv, await this.condaService.getCondaFile());
}
}
}
public async getWindowsActivateCommand(): Promise<string> {
let activateCmd: string = 'activate';
const condaExePath = await this.condaService.getCondaFile();
if (condaExePath && path.basename(condaExePath) !== condaExePath) {
const condaScriptsPath: string = path.dirname(condaExePath);
// prefix the cmd with the found path, and ensure it's quoted properly
activateCmd = path.join(condaScriptsPath, activateCmd);
activateCmd = activateCmd.toCommandArgument();
}
return activateCmd;
}
public async getWindowsCommands(condaEnv: string): Promise<string[] | undefined> {
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()}`];
}
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()}`];
}
}