mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Machine Learning Services R Packages (#8870)
* R Package management in Machine learning services extension
This commit is contained in:
@@ -8,61 +8,97 @@
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import * as nbExtensionApis from '../typings/notebookServices';
|
||||
import { SqlPythonPackageManageProvider } from './sqlPackageManageProvider';
|
||||
import { SqlPythonPackageManageProvider } from './sqlPythonPackageManageProvider';
|
||||
import { QueryRunner } from '../common/queryRunner';
|
||||
import * as utils from '../common/utils';
|
||||
import * as constants from '../common/constants';
|
||||
import { ApiWrapper } from '../common/apiWrapper';
|
||||
import { ProcessService } from '../common/processService';
|
||||
import { Config } from '../common/config';
|
||||
import { Config } from '../configurations/config';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { SqlRPackageManageProvider } from './sqlRPackageManageProvider';
|
||||
import { HttpClient } from '../common/httpClient';
|
||||
import { PackageConfigModel } from '../configurations/packageConfigModel';
|
||||
|
||||
export class PackageManager {
|
||||
|
||||
private _pythonExecutable: string = '';
|
||||
private _pythonInstallationLocation: string = '';
|
||||
private _sqlPackageManager: SqlPythonPackageManageProvider | undefined = undefined;
|
||||
private _rExecutable: string = '';
|
||||
private _sqlPythonPackagePackageManager: SqlPythonPackageManageProvider;
|
||||
private _sqlRPackageManager: SqlRPackageManageProvider;
|
||||
public dependenciesInstalled: boolean = false;
|
||||
|
||||
/**
|
||||
* Creates a new instance of PackageManager
|
||||
*/
|
||||
constructor(
|
||||
private _nbExtensionApis: nbExtensionApis.IExtensionApi,
|
||||
private _outputChannel: vscode.OutputChannel,
|
||||
private _rootFolder: string,
|
||||
private _apiWrapper: ApiWrapper,
|
||||
private _queryRunner: QueryRunner,
|
||||
private _processService: ProcessService,
|
||||
private _config: Config) {
|
||||
private _config: Config,
|
||||
private _httpClient: HttpClient) {
|
||||
this._sqlPythonPackagePackageManager = new SqlPythonPackageManageProvider(this._outputChannel, this._apiWrapper, this._queryRunner, this._processService, this._config, this._httpClient);
|
||||
this._sqlRPackageManager = new SqlRPackageManageProvider(this._outputChannel, this._apiWrapper, this._queryRunner, this._processService, this._config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the instance and resister SQL package manager with manage package dialog
|
||||
*/
|
||||
public init(): void {
|
||||
this._pythonInstallationLocation = utils.getPythonInstallationLocation(this._rootFolder);
|
||||
this._pythonExecutable = utils.getPythonExePath(this._rootFolder);
|
||||
this._sqlPackageManager = new SqlPythonPackageManageProvider(this._nbExtensionApis, this._outputChannel, this._rootFolder, this._apiWrapper, this._queryRunner, this._processService);
|
||||
this._nbExtensionApis.registerPackageManager(SqlPythonPackageManageProvider.ProviderId, this._sqlPackageManager);
|
||||
this._pythonExecutable = this._config.pythonExecutable;
|
||||
this._rExecutable = this._config.rExecutable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns packageManageProviders
|
||||
*/
|
||||
public get packageManageProviders(): nbExtensionApis.IPackageManageProvider[] {
|
||||
return [
|
||||
this._sqlPythonPackagePackageManager,
|
||||
this._sqlRPackageManager
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes manage package command for SQL server packages.
|
||||
*/
|
||||
public async managePackages(): Promise<void> {
|
||||
try {
|
||||
// Only execute the command if there's a valid connection with ml configuration enabled
|
||||
//
|
||||
let connection = await this.getCurrentConnection();
|
||||
let isPythonInstalled = await this._queryRunner.isPythonInstalled(connection);
|
||||
let isRInstalled = await this._queryRunner.isRInstalled(connection);
|
||||
let defaultProvider: SqlRPackageManageProvider | SqlPythonPackageManageProvider | undefined;
|
||||
if (connection && isPythonInstalled) {
|
||||
defaultProvider = this._sqlPythonPackagePackageManager;
|
||||
} else if (connection && isRInstalled) {
|
||||
defaultProvider = this._sqlRPackageManager;
|
||||
}
|
||||
if (connection && defaultProvider) {
|
||||
|
||||
// Only execute the command if there's a valid connection with ml configuration enabled
|
||||
//
|
||||
let connection = await this.getCurrentConnection();
|
||||
let isPythonInstalled = await this._queryRunner.isPythonInstalled(connection);
|
||||
if (connection && isPythonInstalled && this._sqlPackageManager) {
|
||||
this._apiWrapper.executeCommand(constants.managePackagesCommand, {
|
||||
multiLocations: false,
|
||||
defaultLocation: this._sqlPackageManager.packageTarget.location,
|
||||
defaultProviderId: SqlPythonPackageManageProvider.ProviderId
|
||||
});
|
||||
} else {
|
||||
this._apiWrapper.showInfoMessage(constants.managePackageCommandError);
|
||||
// Install dependencies
|
||||
//
|
||||
if (!this.dependenciesInstalled) {
|
||||
this._apiWrapper.showInfoMessage(constants.installingDependencies);
|
||||
await this.installDependencies();
|
||||
this.dependenciesInstalled = true;
|
||||
}
|
||||
|
||||
// Execute the command
|
||||
//
|
||||
this._apiWrapper.executeCommand(constants.managePackagesCommand, {
|
||||
multiLocations: false,
|
||||
defaultLocation: defaultProvider.packageTarget.location,
|
||||
defaultProviderId: defaultProvider.providerId
|
||||
});
|
||||
} else {
|
||||
this._apiWrapper.showInfoMessage(constants.managePackageCommandError);
|
||||
}
|
||||
} catch (err) {
|
||||
this._outputChannel.appendLine(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,16 +114,13 @@ export class PackageManager {
|
||||
isCancelable: false,
|
||||
operation: async op => {
|
||||
try {
|
||||
if (!(await utils.exists(this._pythonExecutable))) {
|
||||
// Install python
|
||||
//
|
||||
await utils.createFolder(this._pythonInstallationLocation);
|
||||
await this.jupyterInstallation.installPythonPackage(op, false, this._pythonInstallationLocation, this._outputChannel);
|
||||
}
|
||||
await utils.createFolder(utils.getRPackagesFolderPath(this._rootFolder));
|
||||
|
||||
// Install required packages
|
||||
//
|
||||
await this.installRequiredPythonPackages();
|
||||
await Promise.all([
|
||||
this.installRequiredPythonPackages(),
|
||||
this.installRequiredRPackages(op)]);
|
||||
op.updateStatus(azdata.TaskStatus.Succeeded);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
@@ -100,10 +133,21 @@ export class PackageManager {
|
||||
});
|
||||
}
|
||||
|
||||
private async installRequiredRPackages(startBackgroundOperation: azdata.BackgroundOperation): Promise<void> {
|
||||
if (!this._rExecutable) {
|
||||
throw new Error(constants.rConfigError);
|
||||
}
|
||||
|
||||
await Promise.all(this._config.requiredRPackages.map(x => this.installRPackage(x, startBackgroundOperation)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs required python packages
|
||||
*/
|
||||
private async installRequiredPythonPackages(): Promise<void> {
|
||||
if (!this._pythonExecutable) {
|
||||
throw new Error(constants.pythonConfigError);
|
||||
}
|
||||
let installedPackages = await this.getInstalledPipPackages();
|
||||
let fileContent = '';
|
||||
this._config.requiredPythonPackages.forEach(packageDetails => {
|
||||
@@ -117,7 +161,7 @@ export class PackageManager {
|
||||
if (fileContent) {
|
||||
this._outputChannel.appendLine(constants.installDependenciesPackages);
|
||||
let result = await utils.execCommandOnTempFile<string>(fileContent, async (tempFilePath) => {
|
||||
return await this.installPackages(tempFilePath);
|
||||
return await this.installPipPackage(tempFilePath);
|
||||
});
|
||||
this._outputChannel.appendLine(result);
|
||||
} else {
|
||||
@@ -145,12 +189,26 @@ export class PackageManager {
|
||||
return await this._apiWrapper.getCurrentConnection();
|
||||
}
|
||||
|
||||
private get jupyterInstallation(): nbExtensionApis.IJupyterServerInstallation {
|
||||
return this._nbExtensionApis.getJupyterController().jupyterInstallation;
|
||||
}
|
||||
|
||||
private async installPackages(requirementFilePath: string): Promise<string> {
|
||||
private async installPipPackage(requirementFilePath: string): Promise<string> {
|
||||
let cmd = `"${this._pythonExecutable}" -m pip install -r "${requirementFilePath}"`;
|
||||
return await this._processService.executeBufferedCommand(cmd, this._outputChannel);
|
||||
}
|
||||
|
||||
private async installRPackage(model: PackageConfigModel, startBackgroundOperation: azdata.BackgroundOperation): Promise<string> {
|
||||
let output = '';
|
||||
let cmd = '';
|
||||
if (model.downloadUrl) {
|
||||
const packageFile = utils.getPackageFilePath(this._rootFolder, model.fileName || model.name);
|
||||
const packageExist = await utils.exists(packageFile);
|
||||
if (!packageExist) {
|
||||
await this._httpClient.download(model.downloadUrl, packageFile, startBackgroundOperation, this._outputChannel);
|
||||
}
|
||||
cmd = `"${this._rExecutable}" CMD INSTALL ${packageFile}`;
|
||||
output = await this._processService.executeBufferedCommand(cmd, this._outputChannel);
|
||||
} else if (model.repository) {
|
||||
cmd = `"${this._rExecutable}" -e "install.packages('${model.name}', repos='${model.repository}')"`;
|
||||
output = output + await this._processService.executeBufferedCommand(cmd, this._outputChannel);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user