Skip to content

Commit 5e8b5b3

Browse files
Nikola HristovNikola Hristov
authored andcommitted
1 parent 6b76596 commit 5e8b5b3

File tree

10 files changed

+169
-0
lines changed

10 files changed

+169
-0
lines changed

Source/channelManager.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,28 +30,34 @@ export class InstallationChannelManager implements IInstallationChannelManager {
3030
resource?: InterpreterUri,
3131
): Promise<IModuleInstaller | undefined> {
3232
const channels = await this.getInstallationChannels(resource);
33+
3334
if (channels.length === 1) {
3435
return channels[0];
3536
}
3637

3738
const productName = ProductNames.get(product)!;
39+
3840
const appShell =
3941
this.serviceContainer.get<IApplicationShell>(IApplicationShell);
42+
4043
if (channels.length === 0) {
4144
await this.showNoInstallersMessage(
4245
isResource(resource) ? resource : undefined,
4346
);
47+
4448
return;
4549
}
4650

4751
const placeHolder = `Select an option to install ${productName}`;
52+
4853
const options = channels.map((installer) => {
4954
return {
5055
label: `Install using ${installer.displayName}`,
5156
description: "",
5257
installer,
5358
};
5459
});
60+
5561
const selection = await appShell.showQuickPick<(typeof options)[0]>(
5662
options,
5763
{
@@ -60,6 +66,7 @@ export class InstallationChannelManager implements IInstallationChannelManager {
6066
placeHolder,
6167
},
6268
);
69+
6370
return selection ? selection.installer : undefined;
6471
}
6572

@@ -68,13 +75,17 @@ export class InstallationChannelManager implements IInstallationChannelManager {
6875
): Promise<IModuleInstaller[]> {
6976
const installers =
7077
this.serviceContainer.getAll<IModuleInstaller>(IModuleInstaller);
78+
7179
const supportedInstallers: IModuleInstaller[] = [];
80+
7281
if (installers.length === 0) {
7382
return [];
7483
}
7584
// group by priority and pick supported from the highest priority
7685
installers.sort((a, b) => b.priority - a.priority);
86+
7787
let currentPri = installers[0].priority;
88+
7889
for (const mi of installers) {
7990
if (mi.priority !== currentPri) {
8091
if (supportedInstallers.length > 0) {
@@ -93,15 +104,20 @@ export class InstallationChannelManager implements IInstallationChannelManager {
93104
public async showNoInstallersMessage(resource?: Uri): Promise<void> {
94105
const interpreters =
95106
this.serviceContainer.get<IInterpreterService>(IInterpreterService);
107+
96108
const interpreter = await interpreters.getActiveInterpreter(resource);
109+
97110
if (!interpreter) {
98111
return; // Handled in the Python installation check.
99112
}
100113

101114
const appShell =
102115
this.serviceContainer.get<IApplicationShell>(IApplicationShell);
116+
103117
const search = "Search for help";
118+
104119
let result: string | undefined;
120+
105121
if (interpreter.envType === EnvironmentType.Conda) {
106122
result = await appShell.showErrorMessage(
107123
Installer.noCondaOrPipInstaller(),
@@ -116,6 +132,7 @@ export class InstallationChannelManager implements IInstallationChannelManager {
116132
if (result === search) {
117133
const platform =
118134
this.serviceContainer.get<IPlatformService>(IPlatformService);
135+
119136
const osName = platform.isWindows
120137
? "Windows"
121138
: platform.isMac

Source/condaInstaller.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export class CondaInstaller extends ModuleInstaller {
5959
const condaLocator =
6060
this.serviceContainer.get<ICondaService>(ICondaService);
6161
this._isCondaAvailable = await condaLocator.isCondaAvailable();
62+
6263
if (!this._isCondaAvailable) {
6364
return false;
6465
}
@@ -76,16 +77,20 @@ export class CondaInstaller extends ModuleInstaller {
7677
): Promise<ExecutionInfo> {
7778
const condaService =
7879
this.serviceContainer.get<ICondaService>(ICondaService);
80+
7981
const condaFile = await condaService.getCondaFile();
8082

8183
const pythonPath = isResource(resource)
8284
? this.serviceContainer
8385
.get<IConfigurationService>(IConfigurationService)
8486
.getSettings(resource).pythonPath
8587
: resource.path;
88+
8689
const condaLocatorService =
8790
this.serviceContainer.get<IComponentAdapter>(IComponentAdapter);
91+
8892
const info = await condaLocatorService.getCondaEnvironment(pythonPath);
93+
8994
const args = [
9095
flags & ModuleInstallFlags.upgrade ? "update" : "install",
9196
];
@@ -124,6 +129,7 @@ export class CondaInstaller extends ModuleInstaller {
124129
}
125130
args.push(moduleName);
126131
args.push("-y");
132+
127133
return {
128134
args,
129135
execPath: condaFile,
@@ -138,11 +144,13 @@ export class CondaInstaller extends ModuleInstaller {
138144
): Promise<boolean> {
139145
const condaService =
140146
this.serviceContainer.get<IComponentAdapter>(IComponentAdapter);
147+
141148
const pythonPath = isResource(resource)
142149
? this.serviceContainer
143150
.get<IConfigurationService>(IConfigurationService)
144151
.getSettings(resource).pythonPath
145152
: resource.path;
153+
146154
return condaService.isCondaEnvironment(pythonPath);
147155
}
148156
}

Source/extensionBuildInstaller.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class StableBuildInstaller implements IExtensionBuildInstaller {
3434
progress.report({
3535
message: ExtensionChannels.installingStableMessage(),
3636
});
37+
3738
return this.cmdManager.executeCommand(
3839
"workbench.extensions.installExtension",
3940
PVSC_EXTENSION_ID,
@@ -67,6 +68,7 @@ export class InsidersBuildInstaller implements IExtensionBuildInstaller {
6768
progress.report({
6869
message: ExtensionChannels.installingInsidersMessage(),
6970
});
71+
7072
return this.cmdManager.executeCommand(
7173
"workbench.extensions.installExtension",
7274
Uri.file(vsixFilePath),
@@ -83,15 +85,18 @@ export class InsidersBuildInstaller implements IExtensionBuildInstaller {
8385
@traceDecoratorError("Downloading insiders build of extension failed")
8486
public async downloadInsiders(): Promise<string> {
8587
traceLog(ExtensionChannels.startingDownloadOutputMessage());
88+
8689
const downloadOptions = {
8790
extension: vsixFileExtension,
8891
progressMessagePrefix:
8992
ExtensionChannels.downloadingInsidersMessage(),
9093
};
94+
9195
return this.fileDownloader
9296
.downloadFile(developmentBuildUri, downloadOptions)
9397
.then((file) => {
9498
traceLog(ExtensionChannels.downloadCompletedOutputMessage());
99+
95100
return file;
96101
});
97102
}

Source/moduleInstaller.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
5353
typeof productOrModuleName == "string"
5454
? productOrModuleName
5555
: translateProductToModule(productOrModuleName);
56+
5657
const productName =
5758
typeof productOrModuleName === "string"
5859
? name
@@ -61,8 +62,11 @@ export abstract class ModuleInstaller implements IModuleInstaller {
6162
installer: this.displayName,
6263
productName,
6364
});
65+
6466
const uri = isResource(resource) ? resource : undefined;
67+
6568
const options: TerminalCreationOptions = {};
69+
6670
if (isResource(resource)) {
6771
options.resource = uri;
6872
} else {
@@ -73,35 +77,43 @@ export abstract class ModuleInstaller implements IModuleInstaller {
7377
resource,
7478
flags,
7579
);
80+
7681
const terminalService = this.serviceContainer
7782
.get<ITerminalServiceFactory>(ITerminalServiceFactory)
7883
.getTerminalService(options);
84+
7985
const install = async (token?: CancellationToken) => {
8086
const executionInfoArgs = await this.processInstallArgs(
8187
executionInfo.args,
8288
resource,
8389
);
90+
8491
if (executionInfo.moduleName) {
8592
const configService =
8693
this.serviceContainer.get<IConfigurationService>(
8794
IConfigurationService,
8895
);
96+
8997
const settings = configService.getSettings(uri);
9098

9199
const interpreterService =
92100
this.serviceContainer.get<IInterpreterService>(
93101
IInterpreterService,
94102
);
103+
95104
const interpreter = isResource(resource)
96105
? await interpreterService.getActiveInterpreter(resource)
97106
: resource;
107+
98108
const pythonPath = isResource(resource)
99109
? settings.pythonPath
100110
: resource.path;
111+
101112
const args = internalPython.execModule(
102113
executionInfo.moduleName,
103114
executionInfoArgs,
104115
);
116+
105117
if (
106118
!interpreter ||
107119
interpreter.envType !== EnvironmentType.Unknown
@@ -110,6 +122,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
110122
} else if (settings.globalModuleInstallation) {
111123
const fs =
112124
this.serviceContainer.get<IFileSystem>(IFileSystem);
125+
113126
if (
114127
await fs
115128
.isDirReadonly(path.dirname(pythonPath))
@@ -148,6 +161,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
148161
if (cancel) {
149162
const shell =
150163
this.serviceContainer.get<IApplicationShell>(IApplicationShell);
164+
151165
const options: ProgressOptions = {
152166
location: ProgressLocation.Notification,
153167
cancellable: true,
@@ -168,10 +182,12 @@ export abstract class ModuleInstaller implements IModuleInstaller {
168182
const options = {
169183
name: "VS Code Python",
170184
};
185+
171186
const outputChannel = this.serviceContainer.get<IOutputChannel>(
172187
IOutputChannel,
173188
STANDARD_OUTPUT_CHANNEL,
174189
);
190+
175191
const command = `"${execPath.replace(/\\/g, "/")}" ${args.join(" ")}`;
176192

177193
traceLog(`[Elevated] ${command}`);
@@ -190,6 +206,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
190206
await shell.showErrorMessage(error);
191207
} else {
192208
outputChannel.show();
209+
193210
if (stdout) {
194211
traceLog(stdout);
195212
}
@@ -212,11 +229,13 @@ export abstract class ModuleInstaller implements IModuleInstaller {
212229
const indexOfPylint = args.findIndex(
213230
(arg) => arg.toUpperCase() === "PYLINT",
214231
);
232+
215233
if (indexOfPylint === -1) {
216234
return args;
217235
}
218236
const interpreterService =
219237
this.serviceContainer.get<IInterpreterService>(IInterpreterService);
238+
220239
const interpreter = isResource(resource)
221240
? await interpreterService.getActiveInterpreter(resource)
222241
: resource;
@@ -229,6 +248,7 @@ export abstract class ModuleInstaller implements IModuleInstaller {
229248
const newArgs = [...args];
230249
// This command could be sent to the terminal, hence '<' needs to be escaped for UNIX.
231250
newArgs[indexOfPylint] = '"pylint<2.0.0"';
251+
232252
return newArgs;
233253
}
234254
return args;
@@ -239,52 +259,76 @@ export function translateProductToModule(product: Product): string {
239259
switch (product) {
240260
case Product.mypy:
241261
return "mypy";
262+
242263
case Product.pylama:
243264
return "pylama";
265+
244266
case Product.prospector:
245267
return "prospector";
268+
246269
case Product.pylint:
247270
return "pylint";
271+
248272
case Product.pytest:
249273
return "pytest";
274+
250275
case Product.autopep8:
251276
return "autopep8";
277+
252278
case Product.black:
253279
return "black";
280+
254281
case Product.pycodestyle:
255282
return "pycodestyle";
283+
256284
case Product.pydocstyle:
257285
return "pydocstyle";
286+
258287
case Product.yapf:
259288
return "yapf";
289+
260290
case Product.flake8:
261291
return "flake8";
292+
262293
case Product.unittest:
263294
return "unittest";
295+
264296
case Product.bandit:
265297
return "bandit";
298+
266299
case Product.jupyter:
267300
return "jupyter";
301+
268302
case Product.notebook:
269303
return "notebook";
304+
270305
case Product.pandas:
271306
return "pandas";
307+
272308
case Product.ipykernel:
273309
return "ipykernel";
310+
274311
case Product.nbconvert:
275312
return "nbconvert";
313+
276314
case Product.kernelspec:
277315
return "kernelspec";
316+
278317
case Product.tensorboard:
279318
return "tensorboard";
319+
280320
case Product.torchProfilerInstallName:
281321
return "torch-tb-profiler";
322+
282323
case Product.torchProfilerImportName:
283324
return "torch_tb_profiler";
325+
284326
case Product.pip:
285327
return "pip";
328+
286329
case Product.ensurepip:
287330
return "ensurepip";
331+
288332
default: {
289333
throw new Error(
290334
`Product ${product} cannot be installed as a Python Module.`,

Source/pipEnvInstaller.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ export class PipEnvInstaller extends ModuleInstaller {
4545
const interpreter = await this.serviceContainer
4646
.get<IInterpreterService>(IInterpreterService)
4747
.getActiveInterpreter(resource);
48+
4849
const workspaceFolder = resource
4950
? this.serviceContainer
5051
.get<IWorkspaceService>(IWorkspaceService)
5152
.getWorkspaceFolder(resource)
5253
: undefined;
54+
5355
if (
5456
!interpreter ||
5557
!workspaceFolder ||
@@ -76,7 +78,9 @@ export class PipEnvInstaller extends ModuleInstaller {
7678
flags & ModuleInstallFlags.reInstall ||
7779
flags & ModuleInstallFlags.updateDependencies ||
7880
flags & ModuleInstallFlags.upgrade;
81+
7982
const args = [update ? "update" : "install", moduleName, "--dev"];
83+
8084
if (moduleName === "black") {
8185
args.push("--pre");
8286
}

0 commit comments

Comments
 (0)