Machine Learning Services R Packages (#8870)

* R Package management in Machine learning services extension
This commit is contained in:
Leila Lali
2020-01-15 12:19:22 -08:00
committed by GitHub
parent d3105beb43
commit 09b578a169
29 changed files with 1330 additions and 414 deletions

View File

@@ -0,0 +1,115 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { ApiWrapper } from '../common/apiWrapper';
import * as constants from '../common/constants';
import * as nbExtensionApis from '../typings/notebookServices';
import * as utils from '../common/utils';
export enum ScriptMode {
Install = 'install',
Uninstall = 'uninstall'
}
export abstract class SqlPackageManageProviderBase {
/**
* Base class for all SQL package managers
*/
constructor(protected _apiWrapper: ApiWrapper) {
}
/**
* Returns location title
*/
public async getLocationTitle(): Promise<string> {
let connection = await this.getCurrentConnection();
if (connection) {
return `${connection.serverName} ${connection.databaseName ? connection.databaseName : ''}`;
}
return constants.packageManagerNoConnection;
}
protected async getCurrentConnection(): Promise<azdata.connection.ConnectionProfile> {
return await this._apiWrapper.getCurrentConnection();
}
/**
* Installs given packages
* @param packages Packages to install
* @param useMinVersion minimum version
*/
public async installPackages(packages: nbExtensionApis.IPackageDetails[], useMinVersion: boolean): Promise<void> {
if (packages) {
await Promise.all(packages.map(x => this.installPackage(x, useMinVersion)));
}
//TODO: use useMinVersion
console.log(useMinVersion);
}
private async installPackage(packageDetail: nbExtensionApis.IPackageDetails, useMinVersion: boolean): Promise<void> {
if (useMinVersion) {
let packageOverview = await this.getPackageOverview(packageDetail.name);
if (packageOverview && packageOverview.versions) {
let minVersion = packageOverview.versions[packageOverview.versions.length - 1];
packageDetail.version = minVersion;
}
}
await this.executeScripts(ScriptMode.Install, packageDetail);
}
/**
* Uninstalls given packages
* @param packages Packages to uninstall
*/
public async uninstallPackages(packages: nbExtensionApis.IPackageDetails[]): Promise<void> {
if (packages) {
await Promise.all(packages.map(x => this.executeScripts(ScriptMode.Uninstall, x)));
}
}
/**
* Returns package overview for given name
* @param packageName Package Name
*/
public async getPackageOverview(packageName: string): Promise<nbExtensionApis.IPackageOverview> {
let packageOverview = await this.fetchPackage(packageName);
if (packageOverview && packageOverview.versions) {
packageOverview.versions = utils.sortPackageVersions(packageOverview.versions, false);
}
return packageOverview;
}
/**
* Returns list of packages
*/
public async listPackages(): Promise<nbExtensionApis.IPackageDetails[]> {
let packages = await this.fetchPackages();
if (packages) {
packages = packages.sort((a, b) => this.comparePackages(a, b));
} else {
packages = [];
}
return packages;
}
private comparePackages(p1: nbExtensionApis.IPackageDetails, p2: nbExtensionApis.IPackageDetails): number {
if (p1 && p2) {
let compare = p1.name.localeCompare(p2.name);
if (compare === 0) {
compare = utils.comparePackageVersions(p1.version, p2.version);
}
return compare;
}
return p1 ? 1 : -1;
}
protected abstract fetchPackage(packageName: string): Promise<nbExtensionApis.IPackageOverview>;
protected abstract fetchPackages(): Promise<nbExtensionApis.IPackageDetails[]>;
protected abstract executeScripts(scriptMode: ScriptMode, packageDetails: nbExtensionApis.IPackageDetails): Promise<void>;
}

View File

@@ -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;
}
}

View File

@@ -1,183 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as nbExtensionApis from '../typings/notebookServices';
import * as utils from '../common/utils';
import * as constants from '../common/constants';
import { QueryRunner } from '../common/queryRunner';
import { ApiWrapper } from '../common/apiWrapper';
import { ProcessService } from '../common/processService';
const installMode = 'install';
const uninstallMode = 'uninstall';
const localPythonProviderId = 'localhost_Pip';
/**
* Manage Package Provider for python packages inside SQL server databases
*/
export class SqlPythonPackageManageProvider implements nbExtensionApis.IPackageManageProvider {
private _pythonExecutable: string;
public static ProviderId = 'sql_Python';
/**
* Creates new a instance
*/
constructor(
private _nbExtensionApis: nbExtensionApis.IExtensionApi,
private _outputChannel: vscode.OutputChannel,
private _rootFolder: string,
private _apiWrapper: ApiWrapper,
private _queryRunner: QueryRunner,
private _processService: ProcessService) {
this._pythonExecutable = utils.getPythonExePath(this._rootFolder);
}
/**
* Returns provider Id
*/
public get providerId(): string {
return SqlPythonPackageManageProvider.ProviderId;
}
/**
* Returns package target
*/
public get packageTarget(): nbExtensionApis.IPackageTarget {
return { location: 'SQL', packageType: 'Python' };
}
/**
* Returns list of packages
*/
public async listPackages(): Promise<nbExtensionApis.IPackageDetails[]> {
let packages = await this._queryRunner.getPythonPackages(await this.getCurrentConnection());
if (packages) {
packages = packages.sort((a, b) => a.name.localeCompare(b.name));
} else {
packages = [];
}
return packages;
}
/**
* Installs given packages
* @param packages Packages to install
* @param useMinVersion minimum version
*/
async installPackages(packages: nbExtensionApis.IPackageDetails[], useMinVersion: boolean): Promise<void> {
if (packages) {
// TODO: install package as parallel
for (let index = 0; index < packages.length; index++) {
const element = packages[index];
await this.updatePackage(element, installMode);
}
}
//TODO: use useMinVersion
console.log(useMinVersion);
}
/**
* Execute a script to install or uninstall a python package inside current SQL Server connection
* @param packageDetails Packages to install or uninstall
* @param scriptMode can be 'install' or 'uninstall'
*/
private async updatePackage(packageDetails: nbExtensionApis.IPackageDetails, scriptMode: string): Promise<void> {
let connection = await this.getCurrentConnection();
let credentials = await this._apiWrapper.getCredentials(connection.connectionId);
if (connection) {
let port = '1433';
let server = connection.serverName;
let database = connection.databaseName ? `, database="${connection.databaseName}"` : '';
let index = connection.serverName.indexOf(',');
if (index > 0) {
port = connection.serverName.substring(index + 1);
server = connection.serverName.substring(0, index);
}
let pythonConnectionParts = `server="${server}", port=${port}, uid="${connection.userName}", pwd="${credentials[azdata.ConnectionOptionSpecialType.password]}"${database})`;
let pythonCommandScript = scriptMode === installMode ?
`pkgmanager.install(package="${packageDetails.name}", version="${packageDetails.version}")` :
`pkgmanager.uninstall(package_name="${packageDetails.name}")`;
let scripts: string[] = [
'import sqlmlutils',
`connection = sqlmlutils.ConnectionInfo(driver="ODBC Driver 17 for SQL Server", ${pythonConnectionParts}`,
'pkgmanager = sqlmlutils.SQLPackageManager(connection)',
pythonCommandScript
];
await this._processService.execScripts(this._pythonExecutable, scripts, this._outputChannel);
}
}
/**
* Uninstalls given packages
* @param packages Packages to uninstall
*/
async uninstallPackages(packages: nbExtensionApis.IPackageDetails[]): Promise<void> {
for (let index = 0; index < packages.length; index++) {
const element = packages[index];
await this.updatePackage(element, uninstallMode);
}
}
/**
* Returns true if the provider can be used
*/
async canUseProvider(): Promise<boolean> {
let connection = await this.getCurrentConnection();
if (connection && await this._queryRunner.isPythonInstalled(connection)) {
return true;
}
return false;
}
/**
* Returns package overview for given name
* @param packageName Package Name
*/
async getPackageOverview(packageName: string): Promise<nbExtensionApis.IPackageOverview> {
let packagePreview: nbExtensionApis.IPackageOverview = {
name: packageName,
versions: [],
summary: ''
};
let pythonPackageProvider = this.pythonPackageProvider;
if (pythonPackageProvider) {
packagePreview = await pythonPackageProvider.getPackageOverview(packageName);
}
return packagePreview;
}
/**
* Returns location title
*/
async getLocationTitle(): Promise<string> {
let connection = await this.getCurrentConnection();
if (connection) {
return `${connection.serverName} ${connection.databaseName ? connection.databaseName : ''}`;
}
return constants.packageManagerNoConnection;
}
private get pythonPackageProvider(): nbExtensionApis.IPackageManageProvider | undefined {
let providers = this._nbExtensionApis.getPackageManagers();
if (providers && providers.has(localPythonProviderId)) {
return providers.get(localPythonProviderId);
}
return undefined;
}
private async getCurrentConnection(): Promise<azdata.connection.ConnectionProfile> {
return await this._apiWrapper.getCurrentConnection();
}
}

View File

@@ -0,0 +1,135 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as nbExtensionApis from '../typings/notebookServices';
import { QueryRunner } from '../common/queryRunner';
import { ApiWrapper } from '../common/apiWrapper';
import { ProcessService } from '../common/processService';
import { Config } from '../configurations/config';
import { SqlPackageManageProviderBase, ScriptMode } from './SqlPackageManageProviderBase';
import { HttpClient } from '../common/httpClient';
import * as utils from '../common/utils';
/**
* Manage Package Provider for python packages inside SQL server databases
*/
export class SqlPythonPackageManageProvider extends SqlPackageManageProviderBase implements nbExtensionApis.IPackageManageProvider {
public static ProviderId = 'sql_Python';
/**
* Creates new a instance
*/
constructor(
private _outputChannel: vscode.OutputChannel,
apiWrapper: ApiWrapper,
private _queryRunner: QueryRunner,
private _processService: ProcessService,
private _config: Config,
private _httpClient: HttpClient) {
super(apiWrapper);
}
/**
* Returns provider Id
*/
public get providerId(): string {
return SqlPythonPackageManageProvider.ProviderId;
}
/**
* Returns package target
*/
public get packageTarget(): nbExtensionApis.IPackageTarget {
return { location: 'SQL', packageType: 'Python' };
}
/**
* Returns list of packages
*/
protected async fetchPackages(): Promise<nbExtensionApis.IPackageDetails[]> {
return await this._queryRunner.getPythonPackages(await this.getCurrentConnection());
}
/**
* Execute a script to install or uninstall a python package inside current SQL Server connection
* @param packageDetails Packages to install or uninstall
* @param scriptMode can be 'install' or 'uninstall'
*/
protected async executeScripts(scriptMode: ScriptMode, packageDetails: nbExtensionApis.IPackageDetails): Promise<void> {
let connection = await this.getCurrentConnection();
let credentials = await this._apiWrapper.getCredentials(connection.connectionId);
if (connection) {
let port = '1433';
let server = connection.serverName;
let database = connection.databaseName ? `, database="${connection.databaseName}"` : '';
let index = connection.serverName.indexOf(',');
if (index > 0) {
port = connection.serverName.substring(index + 1);
server = connection.serverName.substring(0, index);
}
let pythonConnectionParts = `server="${server}", port=${port}, uid="${connection.userName}", pwd="${credentials[azdata.ConnectionOptionSpecialType.password]}"${database})`;
let pythonCommandScript = scriptMode === ScriptMode.Install ?
`pkgmanager.install(package="${packageDetails.name}", version="${packageDetails.version}")` :
`pkgmanager.uninstall(package_name="${packageDetails.name}")`;
let scripts: string[] = [
'import sqlmlutils',
`connection = sqlmlutils.ConnectionInfo(driver="ODBC Driver 17 for SQL Server", ${pythonConnectionParts}`,
'pkgmanager = sqlmlutils.SQLPackageManager(connection)',
pythonCommandScript
];
let pythonExecutable = this._config.pythonExecutable;
await this._processService.execScripts(pythonExecutable, scripts, [], this._outputChannel);
}
}
/**
* Returns true if the provider can be used
*/
async canUseProvider(): Promise<boolean> {
let connection = await this.getCurrentConnection();
if (connection && await this._queryRunner.isPythonInstalled(connection)) {
return true;
}
return false;
}
private getPackageLink(packageName: string): string {
return `https://pypi.org/pypi/${packageName}/json`;
}
protected async fetchPackage(packageName: string): Promise<nbExtensionApis.IPackageOverview> {
let body = await this._httpClient.fetch(this.getPackageLink(packageName));
let packagesJson = JSON.parse(body);
let versionNums: string[] = [];
let packageSummary = '';
if (packagesJson) {
if (packagesJson.releases) {
let versionKeys = Object.keys(packagesJson.releases);
versionKeys = versionKeys.filter(versionKey => {
let releaseInfo = packagesJson.releases[versionKey];
return Array.isArray(releaseInfo) && releaseInfo.length > 0;
});
versionNums = utils.sortPackageVersions(versionKeys, false);
}
if (packagesJson.info && packagesJson.info.summary) {
packageSummary = packagesJson.info.summary;
}
}
return {
name: packageName,
versions: versionNums,
summary: packageSummary
};
}
}

View File

@@ -0,0 +1,112 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as nbExtensionApis from '../typings/notebookServices';
import { QueryRunner } from '../common/queryRunner';
import { ApiWrapper } from '../common/apiWrapper';
import { ProcessService } from '../common/processService';
import { Config } from '../configurations/config';
import { SqlPackageManageProviderBase, ScriptMode } from './SqlPackageManageProviderBase';
/**
* Manage Package Provider for r packages inside SQL server databases
*/
export class SqlRPackageManageProvider extends SqlPackageManageProviderBase implements nbExtensionApis.IPackageManageProvider {
public static ProviderId = 'sql_R';
/**
* Creates new a instance
*/
constructor(
private _outputChannel: vscode.OutputChannel,
apiWrapper: ApiWrapper,
private _queryRunner: QueryRunner,
private _processService: ProcessService,
private _config: Config) {
super(apiWrapper);
}
/**
* Returns provider Id
*/
public get providerId(): string {
return SqlRPackageManageProvider.ProviderId;
}
/**
* Returns package target
*/
public get packageTarget(): nbExtensionApis.IPackageTarget {
return { location: 'SQL', packageType: 'R' };
}
/**
* Returns list of packages
*/
protected async fetchPackages(): Promise<nbExtensionApis.IPackageDetails[]> {
return await this._queryRunner.getRPackages(await this.getCurrentConnection());
}
/**
* Execute a script to install or uninstall a r package inside current SQL Server connection
* @param packageDetails Packages to install or uninstall
* @param scriptMode can be 'install' or 'uninstall'
*/
protected async executeScripts(scriptMode: ScriptMode, packageDetails: nbExtensionApis.IPackageDetails): Promise<void> {
let connection = await this.getCurrentConnection();
let credentials = await this._apiWrapper.getCredentials(connection.connectionId);
if (connection) {
let database = connection.databaseName ? `, database="${connection.databaseName}"` : '';
let connectionParts = `server="${connection.serverName}", uid="${connection.userName}", pwd="${credentials[azdata.ConnectionOptionSpecialType.password]}"${database}`;
let rCommandScript = scriptMode === ScriptMode.Install ? 'sql_install.packages' : 'sql_remove.packages';
let scripts: string[] = [
'formals(quit)$save <- formals(q)$save <- "no"',
'library(sqlmlutils)',
`connection <- connectionInfo(${connectionParts})`,
`pkgs <- c("${packageDetails.name}")`,
`${rCommandScript}(connectionString = connection, pkgs, scope = "PUBLIC")`,
'q()'
];
let rExecutable = this._config.rExecutable;
await this._processService.execScripts(`${rExecutable}`, scripts, ['--vanilla'], this._outputChannel);
}
}
/**
* Returns true if the provider can be used
*/
async canUseProvider(): Promise<boolean> {
let connection = await this.getCurrentConnection();
if (connection && await this._queryRunner.isRInstalled(connection)) {
return true;
}
return false;
}
/**
* Returns package overview for given name
* @param packageName Package Name
*/
protected async fetchPackage(packageName: string): Promise<nbExtensionApis.IPackageOverview> {
let packagePreview: nbExtensionApis.IPackageOverview = {
name: packageName,
versions: [],
summary: ''
};
let connection = await this.getCurrentConnection();
let availablePackages = await this._queryRunner.getRAvailablePackages(connection);
let versions = availablePackages.filter(x => x.name === packageName).map(x => x.version);
packagePreview.versions = versions;
return packagePreview;
}
}