Skip to content

Commit 0df0fc4

Browse files
author
Kartik Raj
committed
Do not assume the Linux distro to be debian if dnf is not found while installing python
1 parent c00ae65 commit 0df0fc4

File tree

5 files changed

+54
-25
lines changed

5 files changed

+54
-25
lines changed

src/client/common/terminal/factory.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
2929
const terminalTitle = typeof title === 'string' && title.trim().length > 0 ? title.trim() : 'Python';
3030
const interpreter = options?.interpreter;
3131
const id = this.getTerminalId(terminalTitle, resource, interpreter);
32-
if (!this.terminalServices.has(id)) {
32+
if (options.message || !this.terminalServices.has(id)) {
3333
const terminalService = new TerminalService(this.serviceContainer, options);
3434
this.terminalServices.set(id, terminalService);
3535
}
@@ -47,9 +47,6 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
4747
return new TerminalService(this.serviceContainer, { resource, title });
4848
}
4949
private getTerminalId(title: string, resource?: Uri, interpreter?: PythonEnvironment): string {
50-
if (!resource && !interpreter) {
51-
return title;
52-
}
5350
const workspaceFolder = this.serviceContainer
5451
.get<IWorkspaceService>(IWorkspaceService)
5552
.getWorkspaceFolder(resource || undefined);

src/client/common/terminal/service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ export class TerminalService implements ITerminalService, Disposable {
4242
this.terminalAutoActivator = this.serviceContainer.get<ITerminalAutoActivation>(ITerminalAutoActivation);
4343
this.terminalManager.onDidCloseTerminal(this.terminalCloseHandler, this, disposableRegistry);
4444
this.terminalActivator = this.serviceContainer.get<ITerminalActivator>(ITerminalActivator);
45+
if (options?.message) {
46+
this.ensureTerminal().ignoreErrors();
47+
}
4548
}
4649
public dispose() {
4750
if (this.terminal) {
@@ -78,6 +81,7 @@ export class TerminalService implements ITerminalService, Disposable {
7881
name: this.options?.title || 'Python',
7982
env: this.options?.env,
8083
hideFromUser: this.options?.hideFromUser,
84+
message: this.options?.message,
8185
});
8286
this.terminalAutoActivator.disableAutoActivation(this.terminal);
8387

src/client/common/terminal/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ export type TerminalCreationOptions = {
8484
* @type {boolean}
8585
*/
8686
hideFromUser?: boolean;
87+
/**
88+
* A message to write to the terminal on first launch, note that this is not sent to the
89+
* process but, rather written directly to the terminal. This supports escape sequences such
90+
* a setting text style.
91+
*/
92+
message?: string;
8793
};
8894

8995
export interface ITerminalServiceFactory {

src/client/common/utils/localize.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ export namespace Interpreters {
277277
'Interpreters.selectInterpreterTip',
278278
'Tip: you can change the Python interpreter used by the Python extension by clicking on the Python version in the status bar',
279279
);
280+
export const installPythonTerminalMessage = localize(
281+
'Interpreters.installPythonTerminalMessage',
282+
'Please try installing python package using your package manager. Alternatively you can also download it from https://www.python.org/downloads',
283+
);
280284
}
281285

282286
export namespace InterpreterQuickPickList {

src/client/interpreter/configuration/interpreterSelector/commands/installPython/installPythonViaTerminal.ts

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ import { ICommandManager } from '../../../../../common/application/types';
1414
import { sleep } from '../../../../../common/utils/async';
1515
import { OSType } from '../../../../../common/utils/platform';
1616
import { traceVerbose } from '../../../../../logging';
17+
import { Interpreters } from '../../../../../common/utils/localize';
18+
19+
enum PackageManagers {
20+
brew = 'brew',
21+
apt = 'apt',
22+
dnf = 'dnf',
23+
}
1724

1825
/**
1926
* Runs commands listed in walkthrough to install Python.
@@ -22,6 +29,12 @@ import { traceVerbose } from '../../../../../logging';
2229
export class InstallPythonViaTerminal implements IExtensionSingleActivationService {
2330
public readonly supportedWorkspaceTypes = { untrustedWorkspace: true, virtualWorkspace: false };
2431

32+
private readonly packageManagerCommands: Record<PackageManagers, string[]> = {
33+
brew: ['brew install python3'],
34+
dnf: ['sudo dnf install python3'],
35+
apt: ['sudo apt-get update', 'sudo apt-get install python3 python3-venv python3-pip'],
36+
};
37+
2538
constructor(
2639
@inject(ICommandManager) private readonly commandManager: ICommandManager,
2740
@inject(ITerminalServiceFactory) private readonly terminalServiceFactory: ITerminalServiceFactory,
@@ -42,36 +55,41 @@ export class InstallPythonViaTerminal implements IExtensionSingleActivationServi
4255
}
4356

4457
public async _installPythonOnUnix(os: OSType.Linux | OSType.OSX): Promise<void> {
45-
const terminalService = this.terminalServiceFactory.getTerminalService({});
46-
const commands = await getCommands(os);
58+
const commands = await this.getCommands(os);
59+
const terminalService = this.terminalServiceFactory.getTerminalService({
60+
message: commands.length ? undefined : Interpreters.installPythonTerminalMessage,
61+
});
4762
for (const command of commands) {
4863
await terminalService.sendText(command);
4964
await waitForCommandToProcess();
5065
}
5166
}
52-
}
5367

54-
async function getCommands(os: OSType.Linux | OSType.OSX) {
55-
if (os === OSType.OSX) {
56-
return ['brew install python3'];
68+
private async getCommands(os: OSType.Linux | OSType.OSX) {
69+
if (os === OSType.OSX) {
70+
return this.packageManagerCommands[PackageManagers.brew];
71+
}
72+
return this.getCommandsForLinux();
5773
}
58-
return getCommandsForLinux();
59-
}
6074

61-
async function getCommandsForLinux() {
62-
let isDnfAvailable = false;
63-
try {
64-
const which = require('which') as typeof whichTypes;
65-
const resolvedPath = await which('dnf');
66-
traceVerbose('Resolved path to dnf module:', resolvedPath);
67-
isDnfAvailable = resolvedPath.trim().length > 0;
68-
} catch (ex) {
69-
traceVerbose('Dnf not found', ex);
70-
isDnfAvailable = false;
75+
private async getCommandsForLinux() {
76+
for (const packageManager of [PackageManagers.apt, PackageManagers.dnf]) {
77+
let isPackageAvailable = false;
78+
try {
79+
const which = require('which') as typeof whichTypes;
80+
const resolvedPath = await which(packageManager);
81+
traceVerbose(`Resolved path to ${packageManager} module:`, resolvedPath);
82+
isPackageAvailable = resolvedPath.trim().length > 0;
83+
} catch (ex) {
84+
traceVerbose(`${packageManager} not found`, ex);
85+
isPackageAvailable = false;
86+
}
87+
if (isPackageAvailable) {
88+
return this.packageManagerCommands[packageManager];
89+
}
90+
}
91+
return [];
7192
}
72-
return isDnfAvailable
73-
? ['sudo dnf install python3']
74-
: ['sudo apt-get update', 'sudo apt-get install python3 python3-venv python3-pip'];
7593
}
7694

7795
async function waitForCommandToProcess() {

0 commit comments

Comments
 (0)