Skip to content

Commit

Permalink
Do not assume the Linux distro to be debian if dnf is not found while…
Browse files Browse the repository at this point in the history
… installing python
  • Loading branch information
Kartik Raj committed Jul 27, 2022
1 parent c00ae65 commit 0df0fc4
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 25 deletions.
5 changes: 1 addition & 4 deletions src/client/common/terminal/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
const terminalTitle = typeof title === 'string' && title.trim().length > 0 ? title.trim() : 'Python';
const interpreter = options?.interpreter;
const id = this.getTerminalId(terminalTitle, resource, interpreter);
if (!this.terminalServices.has(id)) {
if (options.message || !this.terminalServices.has(id)) {
const terminalService = new TerminalService(this.serviceContainer, options);
this.terminalServices.set(id, terminalService);
}
Expand All @@ -47,9 +47,6 @@ export class TerminalServiceFactory implements ITerminalServiceFactory {
return new TerminalService(this.serviceContainer, { resource, title });
}
private getTerminalId(title: string, resource?: Uri, interpreter?: PythonEnvironment): string {
if (!resource && !interpreter) {
return title;
}
const workspaceFolder = this.serviceContainer
.get<IWorkspaceService>(IWorkspaceService)
.getWorkspaceFolder(resource || undefined);
Expand Down
4 changes: 4 additions & 0 deletions src/client/common/terminal/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export class TerminalService implements ITerminalService, Disposable {
this.terminalAutoActivator = this.serviceContainer.get<ITerminalAutoActivation>(ITerminalAutoActivation);
this.terminalManager.onDidCloseTerminal(this.terminalCloseHandler, this, disposableRegistry);
this.terminalActivator = this.serviceContainer.get<ITerminalActivator>(ITerminalActivator);
if (options?.message) {
this.ensureTerminal().ignoreErrors();
}
}
public dispose() {
if (this.terminal) {
Expand Down Expand Up @@ -78,6 +81,7 @@ export class TerminalService implements ITerminalService, Disposable {
name: this.options?.title || 'Python',
env: this.options?.env,
hideFromUser: this.options?.hideFromUser,
message: this.options?.message,
});
this.terminalAutoActivator.disableAutoActivation(this.terminal);

Expand Down
6 changes: 6 additions & 0 deletions src/client/common/terminal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ export type TerminalCreationOptions = {
* @type {boolean}
*/
hideFromUser?: boolean;
/**
* A message to write to the terminal on first launch, note that this is not sent to the
* process but, rather written directly to the terminal. This supports escape sequences such
* a setting text style.
*/
message?: string;
};

export interface ITerminalServiceFactory {
Expand Down
4 changes: 4 additions & 0 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,10 @@ export namespace Interpreters {
'Interpreters.selectInterpreterTip',
'Tip: you can change the Python interpreter used by the Python extension by clicking on the Python version in the status bar',
);
export const installPythonTerminalMessage = localize(
'Interpreters.installPythonTerminalMessage',
'Please try installing python package using your package manager. Alternatively you can also download it from https://www.python.org/downloads',
);
}

export namespace InterpreterQuickPickList {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ import { ICommandManager } from '../../../../../common/application/types';
import { sleep } from '../../../../../common/utils/async';
import { OSType } from '../../../../../common/utils/platform';
import { traceVerbose } from '../../../../../logging';
import { Interpreters } from '../../../../../common/utils/localize';

enum PackageManagers {
brew = 'brew',
apt = 'apt',
dnf = 'dnf',
}

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

private readonly packageManagerCommands: Record<PackageManagers, string[]> = {
brew: ['brew install python3'],
dnf: ['sudo dnf install python3'],
apt: ['sudo apt-get update', 'sudo apt-get install python3 python3-venv python3-pip'],
};

constructor(
@inject(ICommandManager) private readonly commandManager: ICommandManager,
@inject(ITerminalServiceFactory) private readonly terminalServiceFactory: ITerminalServiceFactory,
Expand All @@ -42,36 +55,41 @@ export class InstallPythonViaTerminal implements IExtensionSingleActivationServi
}

public async _installPythonOnUnix(os: OSType.Linux | OSType.OSX): Promise<void> {
const terminalService = this.terminalServiceFactory.getTerminalService({});
const commands = await getCommands(os);
const commands = await this.getCommands(os);
const terminalService = this.terminalServiceFactory.getTerminalService({
message: commands.length ? undefined : Interpreters.installPythonTerminalMessage,
});
for (const command of commands) {
await terminalService.sendText(command);
await waitForCommandToProcess();
}
}
}

async function getCommands(os: OSType.Linux | OSType.OSX) {
if (os === OSType.OSX) {
return ['brew install python3'];
private async getCommands(os: OSType.Linux | OSType.OSX) {
if (os === OSType.OSX) {
return this.packageManagerCommands[PackageManagers.brew];
}
return this.getCommandsForLinux();
}
return getCommandsForLinux();
}

async function getCommandsForLinux() {
let isDnfAvailable = false;
try {
const which = require('which') as typeof whichTypes;
const resolvedPath = await which('dnf');
traceVerbose('Resolved path to dnf module:', resolvedPath);
isDnfAvailable = resolvedPath.trim().length > 0;
} catch (ex) {
traceVerbose('Dnf not found', ex);
isDnfAvailable = false;
private async getCommandsForLinux() {
for (const packageManager of [PackageManagers.apt, PackageManagers.dnf]) {
let isPackageAvailable = false;
try {
const which = require('which') as typeof whichTypes;
const resolvedPath = await which(packageManager);
traceVerbose(`Resolved path to ${packageManager} module:`, resolvedPath);
isPackageAvailable = resolvedPath.trim().length > 0;
} catch (ex) {
traceVerbose(`${packageManager} not found`, ex);
isPackageAvailable = false;
}
if (isPackageAvailable) {
return this.packageManagerCommands[packageManager];
}
}
return [];
}
return isDnfAvailable
? ['sudo dnf install python3']
: ['sudo apt-get update', 'sudo apt-get install python3 python3-venv python3-pip'];
}

async function waitForCommandToProcess() {
Expand Down

0 comments on commit 0df0fc4

Please sign in to comment.