mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-06 09:35:41 -05:00
ML - dashboard icons and links (#10153)
* ML - dashboard icons and links
This commit is contained in:
136
extensions/machine-learning/src/common/apiWrapper.ts
Normal file
136
extensions/machine-learning/src/common/apiWrapper.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* Wrapper class to act as a facade over VSCode and Data APIs and allow us to test / mock callbacks into
|
||||
* this API from our code
|
||||
*/
|
||||
export class ApiWrapper {
|
||||
public createOutputChannel(name: string): vscode.OutputChannel {
|
||||
return vscode.window.createOutputChannel(name);
|
||||
}
|
||||
|
||||
public createTerminalWithOptions(options: vscode.TerminalOptions): vscode.Terminal {
|
||||
return vscode.window.createTerminal(options);
|
||||
}
|
||||
|
||||
public getCurrentConnection(): Thenable<azdata.connection.ConnectionProfile> {
|
||||
return azdata.connection.getCurrentConnection();
|
||||
}
|
||||
|
||||
public getCredentials(connectionId: string): Thenable<{ [name: string]: string }> {
|
||||
return azdata.connection.getCredentials(connectionId);
|
||||
}
|
||||
|
||||
public registerCommand(command: string, callback: (...args: any[]) => any, thisArg?: any): vscode.Disposable {
|
||||
return vscode.commands.registerCommand(command, callback, thisArg);
|
||||
}
|
||||
|
||||
public executeCommand<T>(command: string, ...rest: any[]): Thenable<T | undefined> {
|
||||
return vscode.commands.executeCommand(command, ...rest);
|
||||
}
|
||||
public registerTaskHandler(taskId: string, handler: (profile: azdata.IConnectionProfile) => void): void {
|
||||
azdata.tasks.registerTask(taskId, handler);
|
||||
}
|
||||
|
||||
public getUriForConnection(connectionId: string): Thenable<string> {
|
||||
return azdata.connection.getUriForConnection(connectionId);
|
||||
}
|
||||
|
||||
public getProvider<T extends azdata.DataProvider>(providerId: string, providerType: azdata.DataProviderType): T {
|
||||
return azdata.dataprotocol.getProvider<T>(providerId, providerType);
|
||||
}
|
||||
|
||||
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showErrorMessage(message, ...items);
|
||||
}
|
||||
|
||||
public showInfoMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showInformationMessage(message, ...items);
|
||||
}
|
||||
|
||||
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
|
||||
return vscode.window.showOpenDialog(options);
|
||||
}
|
||||
|
||||
public startBackgroundOperation(operationInfo: azdata.BackgroundOperationInfo): void {
|
||||
azdata.tasks.startBackgroundOperation(operationInfo);
|
||||
}
|
||||
|
||||
public openExternal(target: vscode.Uri): Thenable<boolean> {
|
||||
return vscode.env.openExternal(target);
|
||||
}
|
||||
|
||||
public getExtension(extensionId: string): vscode.Extension<any> | undefined {
|
||||
return vscode.extensions.getExtension(extensionId);
|
||||
}
|
||||
|
||||
public getConfiguration(section?: string, resource?: vscode.Uri | null): vscode.WorkspaceConfiguration {
|
||||
return vscode.workspace.getConfiguration(section, resource);
|
||||
}
|
||||
|
||||
public createTab(title: string): azdata.window.DialogTab {
|
||||
return azdata.window.createTab(title);
|
||||
}
|
||||
|
||||
public createModelViewDialog(title: string, dialogName?: string, isWide?: boolean): azdata.window.Dialog {
|
||||
return azdata.window.createModelViewDialog(title, dialogName, isWide);
|
||||
}
|
||||
|
||||
public createWizard(title: string): azdata.window.Wizard {
|
||||
return azdata.window.createWizard(title);
|
||||
}
|
||||
|
||||
public createWizardPage(title: string): azdata.window.WizardPage {
|
||||
return azdata.window.createWizardPage(title);
|
||||
}
|
||||
|
||||
public openDialog(dialog: azdata.window.Dialog): void {
|
||||
return azdata.window.openDialog(dialog);
|
||||
}
|
||||
|
||||
public getAllAccounts(): Thenable<azdata.Account[]> {
|
||||
return azdata.accounts.getAllAccounts();
|
||||
}
|
||||
|
||||
public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{ [key: string]: any }> {
|
||||
return azdata.accounts.getSecurityToken(account, resource);
|
||||
}
|
||||
|
||||
public showQuickPick<T extends vscode.QuickPickItem>(items: T[] | Thenable<T[]>, options?: vscode.QuickPickOptions, token?: vscode.CancellationToken): Thenable<T | undefined> {
|
||||
return vscode.window.showQuickPick(items, options, token);
|
||||
}
|
||||
|
||||
public listDatabases(connectionId: string): Thenable<string[]> {
|
||||
return azdata.connection.listDatabases(connectionId);
|
||||
}
|
||||
|
||||
public openTextDocument(options?: { language?: string; content?: string; }): Thenable<vscode.TextDocument> {
|
||||
return vscode.workspace.openTextDocument(options);
|
||||
}
|
||||
|
||||
public connect(fileUri: string, connectionId: string): Thenable<void> {
|
||||
return azdata.queryeditor.connect(fileUri, connectionId);
|
||||
}
|
||||
|
||||
public runQuery(fileUri: string, options?: Map<string, string>, runCurrentQuery?: boolean): void {
|
||||
azdata.queryeditor.runQuery(fileUri, options, runCurrentQuery);
|
||||
}
|
||||
|
||||
public showTextDocument(uri: vscode.Uri, options?: vscode.TextDocumentShowOptions): Thenable<vscode.TextEditor> {
|
||||
return vscode.window.showTextDocument(uri, options);
|
||||
}
|
||||
|
||||
public createButton(label: string, position?: azdata.window.DialogButtonPosition): azdata.window.Button {
|
||||
return azdata.window.createButton(label, position);
|
||||
}
|
||||
|
||||
public registerWidget(widgetId: string, handler: (view: azdata.ModelView) => void): void {
|
||||
azdata.ui.registerModelViewProvider(widgetId, handler);
|
||||
}
|
||||
}
|
||||
235
extensions/machine-learning/src/common/constants.ts
Normal file
235
extensions/machine-learning/src/common/constants.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vscode-nls';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
export const winPlatform = 'win32';
|
||||
export const pythonBundleVersion = '0.0.1';
|
||||
export const managePackagesCommand = 'jupyter.cmd.managePackages';
|
||||
export const pythonLanguageName = 'Python';
|
||||
export const rLanguageName = 'R';
|
||||
export const rLPackagedFolderName = 'r_packages';
|
||||
|
||||
export const mlEnableMlsCommand = 'mls.command.enableMls';
|
||||
export const mlDisableMlsCommand = 'mls.command.disableMls';
|
||||
export const extensionOutputChannel = 'Machine Learning';
|
||||
export const notebookExtensionName = 'Microsoft.notebook';
|
||||
export const azureSubscriptionsCommand = 'azure.accounts.getSubscriptions';
|
||||
export const azureResourceGroupsCommand = 'azure.accounts.getResourceGroups';
|
||||
export const signInToAzureCommand = 'azure.resource.signin';
|
||||
|
||||
// Tasks, commands
|
||||
//
|
||||
export const mlManageLanguagesCommand = 'mls.command.manageLanguages';
|
||||
export const mlsPredictModelCommand = 'mls.command.predictModel';
|
||||
export const mlManageModelsCommand = 'mls.command.manageModels';
|
||||
export const mlImportModelCommand = 'mls.command.importModel';
|
||||
export const mlManagePackagesCommand = 'mls.command.managePackages';
|
||||
export const mlsDependenciesCommand = 'mls.command.dependencies';
|
||||
export const notebookCommandNew = 'notebook.command.new';
|
||||
|
||||
// Configurations
|
||||
//
|
||||
export const mlsConfigKey = 'machineLearningServices';
|
||||
export const pythonPathConfigKey = 'pythonPath';
|
||||
export const pythonEnabledConfigKey = 'enablePython';
|
||||
export const rEnabledConfigKey = 'enableR';
|
||||
export const registeredModelsTableName = 'registeredModelsTableName';
|
||||
export const rPathConfigKey = 'rPath';
|
||||
|
||||
// Localized texts
|
||||
//
|
||||
export const msgYes = localize('msgYes', "Yes");
|
||||
export const msgNo = localize('msgNo', "No");
|
||||
export const managePackageCommandError = localize('mls.managePackages.error', "Either no connection is available or the server does not have external script enabled.");
|
||||
export function taskFailedError(taskName: string, err: string): string { return localize('mls.taskFailedError.error', "Failed to complete task '{0}'. Error: {1}", taskName, err); }
|
||||
export const installPackageMngDependenciesMsgTaskName = localize('mls.installPackageMngDependencies.msgTaskName', "Installing package management dependencies");
|
||||
export const installModelMngDependenciesMsgTaskName = localize('mls.installModelMngDependencies.msgTaskName', "Installing model management dependencies");
|
||||
export const noResultError = localize('mls.noResultError', "No Result returned");
|
||||
export const requiredPackagesNotInstalled = localize('mls.requiredPackagesNotInstalled', "The required dependencies are not installed");
|
||||
export const confirmEnableExternalScripts = localize('mls.confirmEnableExternalScripts', "External script is required for package management. Are you sure you want to enable that.");
|
||||
export const enableExternalScriptsError = localize('mls.enableExternalScriptsError', "Failed to enable External script.");
|
||||
export const externalScriptsIsRequiredError = localize('mls.externalScriptsIsRequiredError', "External script configuration is required for this action.");
|
||||
export function confirmInstallPythonPackages(packages: string): string {
|
||||
return localize('mls.installDependencies.confirmInstallPythonPackages'
|
||||
, "The following Python packages are required to install: {0}. Are you sure you want to install?", packages);
|
||||
}
|
||||
export function confirmDeleteModel(modelName: string): string {
|
||||
return localize('models.confirmDeleteModel'
|
||||
, "Are you sure you want to delete model '{0}?", modelName);
|
||||
}
|
||||
export const installDependenciesPackages = localize('mls.installDependencies.packages', "Installing required packages ...");
|
||||
export const installDependenciesPackagesAlreadyInstalled = localize('mls.installDependencies.packagesAlreadyInstalled', "Required packages are already installed.");
|
||||
export function installDependenciesGetPackagesError(err: string): string { return localize('mls.installDependencies.getPackagesError', "Failed to get installed python packages. Error: {0}", err); }
|
||||
export const noConnectionError = localize('mls.packageManager.NoConnection', "No connection selected");
|
||||
export const notebookExtensionNotLoaded = localize('mls.notebookExtensionNotLoaded', "Notebook extension is not loaded");
|
||||
export const mssqlExtensionNotLoaded = localize('mls.mssqlExtensionNotLoaded', "MSSQL extension is not loaded");
|
||||
export const mlsEnabledMessage = localize('mls.enabledMessage', "Machine Learning Services Enabled");
|
||||
export const mlsConfigUpdateFailed = localize('mls.configUpdateFailed', "Failed to modify Machine Learning Services configurations");
|
||||
export const mlsEnableButtonTitle = localize('mls.enableButtonTitle', "Enable");
|
||||
export const mlsDisableButtonTitle = localize('mls.disableButtonTitle', "Disable");
|
||||
export const mlsConfigTitle = localize('mls.configTitle', "Config");
|
||||
export const mlsConfigStatus = localize('mls.configStatus', "Enabled");
|
||||
export const mlsConfigAction = localize('mls.configAction', "Action");
|
||||
export const mlsExternalExecuteScriptTitle = localize('mls.externalExecuteScriptTitle', "External Execute Script");
|
||||
export const mlsPythonLanguageTitle = localize('mls.pythonLanguageTitle', "Python");
|
||||
export const mlsRLanguageTitle = localize('mls.rLanguageTitle', "R");
|
||||
export const downloadError = localize('mls.downloadError', "Error while downloading");
|
||||
export function invalidModelIdError(modelUrl: string | undefined): string { return localize('mls.invalidModelIdError', "Invalid model id. model url: {0}", modelUrl || ''); }
|
||||
export function noArtifactError(modelUrl: string | undefined): string { return localize('mls.noArtifactError', "Model doesn't have any artifact. model url: {0}", modelUrl || ''); }
|
||||
export const downloadingProgress = localize('mls.downloadingProgress', "Downloading");
|
||||
export const pythonConfigError = localize('mls.pythonConfigError', "Python executable is not configured");
|
||||
export const rConfigError = localize('mls.rConfigError', "R executable is not configured");
|
||||
export const installingDependencies = localize('mls.installingDependencies', "Installing dependencies ...");
|
||||
export const resourceNotFoundError = localize('mls.resourceNotFound', "Could not find the specified resource");
|
||||
export const latestVersion = localize('mls.latestVersion', "Latest");
|
||||
export const localhost = 'localhost';
|
||||
export function httpGetRequestError(code: number, message: string): string {
|
||||
return localize('mls.httpGetRequestError', "Package info request failed with error: {0} {1}",
|
||||
code,
|
||||
message);
|
||||
}
|
||||
export function getErrorMessage(error: Error): string { return localize('azure.resource.error', "Error: {0}", error?.message || error?.toString()); }
|
||||
export const notSupportedEventArg = localize('notSupportedEventArg', "Not supported event args");
|
||||
export const extLangInstallTabTitle = localize('extLang.installTabTitle', "Installed");
|
||||
export const extLangLanguageCreatedDate = localize('extLang.languageCreatedDate', "Installed");
|
||||
export const extLangLanguagePlatform = localize('extLang.languagePlatform', "Platform");
|
||||
export const deleteTitle = localize('extLang.delete', "Delete");
|
||||
export const extLangInstallButtonText = localize('extLang.installButtonText', "Install");
|
||||
export const extLangCancelButtonText = localize('extLang.CancelButtonText', "Cancel");
|
||||
export const extLangDoneButtonText = localize('extLang.DoneButtonText', "Close");
|
||||
export const extLangOkButtonText = localize('extLang.OkButtonText', "OK");
|
||||
export const extLangSaveButtonText = localize('extLang.SaveButtonText', "Save");
|
||||
export const extLangLanguageName = localize('extLang.languageName', "Name");
|
||||
export const extLangNewLanguageTabTitle = localize('extLang.newLanguageTabTitle', "Add new");
|
||||
export const extLangFileBrowserTabTitle = localize('extLang.fileBrowserTabTitle', "File Browser");
|
||||
export const extLangDialogTitle = localize('extLang.DialogTitle', "Languages");
|
||||
export const extLangTarget = localize('extLang.Target', "Target");
|
||||
export const extLangLocal = localize('extLang.Local', "localhost");
|
||||
export const extLangExtensionFilePath = localize('extLang.extensionFilePath', "Language extension path");
|
||||
export const extLangExtensionFileLocation = localize('extLang.extensionFileLocation', "Language extension location");
|
||||
export const extLangExtensionFileName = localize('extLang.extensionFileName', "Extension file Name");
|
||||
export const extLangEnvVariables = localize('extLang.envVariables', "Environment variables");
|
||||
export const extLangParameters = localize('extLang.parameters', "Parameters");
|
||||
export const extLangSelectedPath = localize('extLang.selectedPath', "Selected Path");
|
||||
export const extLangInstallFailedError = localize('extLang.installFailedError', "Failed to install language");
|
||||
export const extLangUpdateFailedError = localize('extLang.updateFailedError', "Failed to update language");
|
||||
|
||||
export const modelUpdateFailedError = localize('models.modelUpdateFailedError', "Failed to update the model");
|
||||
export const databaseName = localize('databaseName', "Database name");
|
||||
export const tableName = localize('tableName', "Table name");
|
||||
export const modelName = localize('models.name', "Name");
|
||||
export const modelFileName = localize('models.fileName', "File");
|
||||
export const modelDescription = localize('models.description', "Description");
|
||||
export const modelCreated = localize('models.created', "Date created");
|
||||
export const modelDeployed = localize('models.deployed', "Date deployed");
|
||||
export const modelFramework = localize('models.framework', "Framework");
|
||||
export const modelFrameworkVersion = localize('models.frameworkVersion', "Framework version");
|
||||
export const modelVersion = localize('models.version', "Version");
|
||||
export const browseModels = localize('models.browseButton', "...");
|
||||
export const azureAccount = localize('models.azureAccount', "Azure account");
|
||||
export const azureSignIn = localize('models.azureSignIn', "Sign in to Azure");
|
||||
export const columnDatabase = localize('predict.columnDatabase', "Target database");
|
||||
export const columnTable = localize('predict.columnTable', "Target table");
|
||||
export const inputColumns = localize('predict.inputColumns', "Model input mapping");
|
||||
export const outputColumns = localize('predict.outputColumns', "Model output");
|
||||
export const columnName = localize('predict.columnName', "Target columns");
|
||||
export const dataTypeName = localize('predict.dataTypeName', "Type");
|
||||
export const displayName = localize('predict.displayName', "Display name");
|
||||
export const inputName = localize('predict.inputName', "Required model input features");
|
||||
export const outputName = localize('predict.outputName', "Name");
|
||||
export const azureSubscription = localize('models.azureSubscription', "Azure subscription");
|
||||
export const azureGroup = localize('models.azureGroup', "Azure resource group");
|
||||
export const azureModelWorkspace = localize('models.azureModelWorkspace', "Azure ML workspace");
|
||||
export const azureModelFilter = localize('models.azureModelFilter', "Filter");
|
||||
export const azureModels = localize('models.azureModels', "Models");
|
||||
export const azureModelsTitle = localize('models.azureModelsTitle', "Azure models");
|
||||
export const localModelsTitle = localize('models.localModelsTitle', "Local models");
|
||||
export const modelSourcesTitle = localize('models.modelSourcesTitle', "Source location");
|
||||
export const modelSourcePageTitle = localize('models.modelSourcePageTitle', "Where is your model located?");
|
||||
export const modelImportTargetPageTitle = localize('models.modelImportTargetPageTitle', "Where do you want import models to?");
|
||||
export const columnSelectionPageTitle = localize('models.columnSelectionPageTitle', "Map predictions target data to model input");
|
||||
export const modelDetailsPageTitle = localize('models.modelDetailsPageTitle', "Enter model details");
|
||||
export const modelLocalSourceTitle = localize('models.modelLocalSourceTitle', "Source file");
|
||||
export const currentModelsTitle = localize('models.currentModelsTitle', "Models");
|
||||
export const azureRegisterModel = localize('models.azureRegisterModel', "Deploy");
|
||||
export const predictModel = localize('models.predictModel', "Predict");
|
||||
export const registerModelTitle = localize('models.RegisterWizard', "Import models");
|
||||
export const importModelTitle = localize('models.importModelTitle', "Import models");
|
||||
export const editModelTitle = localize('models.editModelTitle', "Edit model");
|
||||
export const importModelDesc = localize('models.importModelDesc', "Build, import and expose a machine learning model");
|
||||
export const makePredictionTitle = localize('models.makePredictionTitle', "Make predictions");
|
||||
export const makePredictionDesc = localize('models.makePredictionDesc', "Generates a predicted value or scores using a managed model");
|
||||
export const createNotebookTitle = localize('models.createNotebookTitle', "Create notebook");
|
||||
export const createNotebookDesc = localize('models.createNotebookDesc', "Run experiments and create models");
|
||||
export const modelRegisteredSuccessfully = localize('models.modelRegisteredSuccessfully', "Model registered successfully");
|
||||
export const modelUpdatedSuccessfully = localize('models.modelUpdatedSuccessfully', "Model updated successfully");
|
||||
export const modelFailedToRegister = localize('models.modelFailedToRegistered', "Model failed to register");
|
||||
export const localModelSource = localize('models.localModelSource', "File upload");
|
||||
export const localModelPageTitle = localize('models.localModelPageTitle', "Upload model file");
|
||||
export const azureModelSource = localize('models.azureModelSource', "Azure Machine Learning");
|
||||
export const azureModelPageTitle = localize('models.azureModelPageTitle', "Import from Azure Machine Learning");
|
||||
export const importedModelsPageTitle = localize('models.importedModelsPageTitle', "Select imported model");
|
||||
export const registeredModelsSource = localize('models.registeredModelsSource', "Imported models");
|
||||
export const downloadModelMsgTaskName = localize('models.downloadModelMsgTaskName', "Downloading Model from Azure");
|
||||
export const invalidAzureResourceError = localize('models.invalidAzureResourceError', "Invalid Azure resource");
|
||||
export const invalidModelToRegisterError = localize('models.invalidModelToRegisterError', "Invalid model to register");
|
||||
export const invalidModelToPredictError = localize('models.invalidModelToPredictError', "Invalid model to predict");
|
||||
export const invalidModelToSelectError = localize('models.invalidModelToSelectError', "Please select a valid model");
|
||||
export const invalidModelImportTargetError = localize('models.invalidModelImportTargetError', "Please select a valid table");
|
||||
export const modelNameRequiredError = localize('models.modelNameRequiredError', "Model name is required.");
|
||||
export const updateModelFailedError = localize('models.updateModelFailedError', "Failed to update the model");
|
||||
export function importModelFailedError(modelName: string | undefined, filePath: string | undefined): string { return localize('models.importModelFailedError', "Failed to register the model: {0} ,file: {1}", modelName || '', filePath || ''); }
|
||||
export function invalidImportTableError(databaseName: string | undefined, tableName: string | undefined): string { return localize('models.invalidImportTableError', "Invalid table for importing models. database name: {0} ,table name: {1}", databaseName || '', tableName || ''); }
|
||||
export function invalidImportTableSchemaError(databaseName: string | undefined, tableName: string | undefined): string { return localize('models.invalidImportTableSchemaError', "Table schema is not supported for model import. database name: {0} ,table name: {1}", databaseName || '', tableName || ''); }
|
||||
|
||||
export const loadModelParameterFailedError = localize('models.loadModelParameterFailedError', "Failed to load model parameters'");
|
||||
export const unsupportedModelParameterType = localize('models.unsupportedModelParameterType', "unsupported");
|
||||
export const dashboardTitle = localize('dashboardTitle', "Machine Learning");
|
||||
export const dashboardDesc = localize('dashboardDesc', "Machine Learning for SQL Databases");
|
||||
export const dashboardLinksTitle = localize('dashboardLinksTitle', "Useful links");
|
||||
export const dashboardVideoLinksTitle = localize('dashboardVideoLinksTitle', "Video tutorials");
|
||||
export const showMoreTitle = localize('showMoreTitle', "Show more");
|
||||
export const showLessTitle = localize('showLessTitle', "Show less");
|
||||
export const learnMoreTitle = localize('learnMoreTitle', "Learn more");
|
||||
export const sqlMlDocTitle = localize('sqlMlDocTitle', "SQL machine learning documentation");
|
||||
export const sqlMlDocDesc = localize('sqlMlDocDesc', "Learn how to use machine learning in SQL Server and SQL on Azure, to run Python and R scripts on relational data.");
|
||||
export const sqlMlsDocTitle = localize('sqlMlsDocTitle', "SQL Server Machine Learning Services (Python and R)");
|
||||
export const sqlMlsDocDesc = localize('sqlMlsDocDesc', "Get started with Machine Learning Services on SQL Server and how to install it on Windows and Linux.");
|
||||
export const sqlMlsAzureDocTitle = localize('sqlMlsAzureDocTitle', "Machine Learning Services in Azure SQL Managed Instance (preview)");
|
||||
export const sqlMlsAzureDocDesc = localize('sqlMlsAzureDocDesc', "Get started with Machine Learning Services in Azure SQL Managed Instances.");
|
||||
export const mlsInstallOdbcDocTitle = localize('mlsInstallObdcDocTitle', "Install the Microsoft ODBC driver for SQL Server");
|
||||
export const mlsInstallOdbcDocDesc = localize('mlsInstallOdbcDocDesc', "This document explains how to install the Microsoft ODBC Driver for SQL Server.");
|
||||
|
||||
// Links
|
||||
//
|
||||
export const mlsDocuments = 'https://docs.microsoft.com/sql/advanced-analytics/?view=sql-server-ver15';
|
||||
export const odbcDriverWindowsDocuments = 'https://docs.microsoft.com/sql/connect/odbc/windows/microsoft-odbc-driver-for-sql-server-on-windows?view=sql-server-ver15';
|
||||
export const odbcDriverLinuxDocuments = 'https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15';
|
||||
export const mlDocLink = 'https://docs.microsoft.com/sql/machine-learning/';
|
||||
export const mlsDocLink = 'https://docs.microsoft.com/sql/machine-learning/what-is-sql-server-machine-learning';
|
||||
export const mlsAzureDocLink = 'https://docs.microsoft.com/azure/sql-database/sql-database-managed-instance-machine-learning-services-overview';
|
||||
export const installMlsWindowsDocs = 'https://docs.microsoft.com/sql/advanced-analytics/install/sql-machine-learning-services-windows-install?view=sql-server-ver15';
|
||||
|
||||
// CSS Styles
|
||||
//
|
||||
export namespace cssStyles {
|
||||
export const title = { 'font-size': '14px', 'font-weight': '600' };
|
||||
export const tableHeader = { 'text-align': 'left', 'font-weight': 'bold', 'text-transform': 'uppercase', 'font-size': '10px', 'user-select': 'text', 'border': 'none' };
|
||||
export const tableRow = { 'border-top': 'solid 1px #ccc', 'border-bottom': 'solid 1px #ccc', 'border-left': 'none', 'border-right': 'none' };
|
||||
export const hyperlink = { 'user-select': 'text', 'color': '#0078d4', 'text-decoration': 'underline', 'cursor': 'pointer' };
|
||||
export const text = { 'margin-block-start': '0px', 'margin-block-end': '0px' };
|
||||
export const overflowEllipsisText = { ...text, 'overflow': 'hidden', 'text-overflow': 'ellipsis' };
|
||||
export const nonSelectableText = { ...cssStyles.text, 'user-select': 'none' };
|
||||
export const tabHeaderText = { 'margin-block-start': '2px', 'margin-block-end': '0px', 'user-select': 'none' };
|
||||
export const selectedResourceHeaderTab = { 'font-weight': 'bold', 'color': '' };
|
||||
export const unselectedResourceHeaderTab = { 'font-weight': '', 'color': '#0078d4' };
|
||||
export const selectedTabDiv = { 'border-bottom': '2px solid #000' };
|
||||
export const unselectedTabDiv = { 'border-bottom': '1px solid #ccc' };
|
||||
export const lastUpdatedText = { ...text, 'color': '#595959' };
|
||||
export const errorText = { ...text, 'color': 'red' };
|
||||
}
|
||||
45
extensions/machine-learning/src/common/eventEmitter.ts
Normal file
45
extensions/machine-learning/src/common/eventEmitter.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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';
|
||||
|
||||
export class EventEmitterCollection extends vscode.Disposable {
|
||||
private _events: Map<string, vscode.EventEmitter<any>[]> = new Map<string, vscode.EventEmitter<any>[]>();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constructor() {
|
||||
super(() => this.dispose());
|
||||
|
||||
}
|
||||
|
||||
public on(evt: string, listener: (e: any) => any, thisArgs?: any) {
|
||||
if (!this._events.has(evt)) {
|
||||
this._events.set(evt, []);
|
||||
}
|
||||
let eventEmitter = new vscode.EventEmitter<any>();
|
||||
eventEmitter.event(listener, thisArgs);
|
||||
this._events.get(evt)?.push(eventEmitter);
|
||||
return this;
|
||||
}
|
||||
|
||||
public fire(evt: string, arg?: any) {
|
||||
if (!this._events.has(evt)) {
|
||||
this._events.set(evt, []);
|
||||
}
|
||||
this._events.get(evt)?.forEach(eventEmitter => {
|
||||
eventEmitter.fire(arg);
|
||||
});
|
||||
}
|
||||
|
||||
public dispose(): any {
|
||||
this._events.forEach(events => {
|
||||
events.forEach(event => {
|
||||
event.dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
80
extensions/machine-learning/src/common/httpClient.ts
Normal file
80
extensions/machine-learning/src/common/httpClient.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 fs from 'fs';
|
||||
import * as request from 'request';
|
||||
import * as constants from './constants';
|
||||
|
||||
const DownloadTimeout = 20000;
|
||||
const GetTimeout = 10000;
|
||||
export class HttpClient {
|
||||
|
||||
public async fetch(url: string): Promise<any> {
|
||||
return new Promise<any>((resolve, reject) => {
|
||||
request.get(url, { timeout: GetTimeout }, (error, response, body) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
if (response.statusCode === 404) {
|
||||
return reject(constants.resourceNotFoundError);
|
||||
}
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
return reject(
|
||||
constants.httpGetRequestError(
|
||||
response.statusCode,
|
||||
response.statusMessage));
|
||||
}
|
||||
|
||||
resolve(body);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public download(downloadUrl: string, targetPath: string, outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let totalMegaBytes: number | undefined = undefined;
|
||||
let receivedBytes = 0;
|
||||
let printThreshold = 0.1;
|
||||
let downloadRequest = request.get(downloadUrl, { timeout: DownloadTimeout })
|
||||
.on('error', downloadError => {
|
||||
outputChannel.appendLine(constants.downloadError);
|
||||
reject(downloadError);
|
||||
})
|
||||
.on('response', (response) => {
|
||||
if (response.statusCode !== 200) {
|
||||
outputChannel.appendLine(constants.downloadError);
|
||||
return reject(response.statusMessage);
|
||||
}
|
||||
let contentLength = response.headers['content-length'];
|
||||
let totalBytes = parseInt(contentLength || '0');
|
||||
totalMegaBytes = totalBytes / (1024 * 1024);
|
||||
outputChannel.appendLine(`'Downloading' (0 / ${totalMegaBytes.toFixed(2)} MB)`);
|
||||
})
|
||||
.on('data', (data) => {
|
||||
receivedBytes += data.length;
|
||||
if (totalMegaBytes) {
|
||||
let receivedMegaBytes = receivedBytes / (1024 * 1024);
|
||||
let percentage = receivedMegaBytes / totalMegaBytes;
|
||||
if (percentage >= printThreshold) {
|
||||
outputChannel.appendLine(`${constants.downloadingProgress} (${receivedMegaBytes.toFixed(2)} / ${totalMegaBytes.toFixed(2)} MB)`);
|
||||
printThreshold += 0.1;
|
||||
}
|
||||
}
|
||||
});
|
||||
downloadRequest.pipe(fs.createWriteStream(targetPath))
|
||||
.on('close', async () => {
|
||||
resolve();
|
||||
})
|
||||
.on('error', (downloadError) => {
|
||||
reject(downloadError);
|
||||
downloadRequest.abort();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
91
extensions/machine-learning/src/common/processService.ts
Normal file
91
extensions/machine-learning/src/common/processService.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 childProcess from 'child_process';
|
||||
|
||||
const ExecScriptsTimeoutInSeconds = 600000;
|
||||
export class ProcessService {
|
||||
|
||||
public timeout = ExecScriptsTimeoutInSeconds;
|
||||
|
||||
public async execScripts(exeFilePath: string, scripts: string[], args?: string[], outputChannel?: vscode.OutputChannel): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
|
||||
const scriptExecution = childProcess.spawn(exeFilePath, args);
|
||||
let timer: NodeJS.Timeout;
|
||||
let output: string = '';
|
||||
scripts.forEach(script => {
|
||||
scriptExecution.stdin.write(`${script}\n`);
|
||||
});
|
||||
scriptExecution.stdin.end();
|
||||
|
||||
// Add listeners to print stdout and stderr if an output channel was provided
|
||||
|
||||
scriptExecution.stdout.on('data', data => {
|
||||
if (outputChannel) {
|
||||
this.outputDataChunk(data, outputChannel, ' stdout: ');
|
||||
}
|
||||
output = output + data.toString();
|
||||
});
|
||||
scriptExecution.stderr.on('data', data => {
|
||||
if (outputChannel) {
|
||||
this.outputDataChunk(data, outputChannel, ' stderr: ');
|
||||
}
|
||||
output = output + data.toString();
|
||||
});
|
||||
|
||||
scriptExecution.on('exit', (code) => {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
if (code === 0) {
|
||||
resolve(output);
|
||||
} else {
|
||||
reject(`Process exited with code: ${code}. output: ${output}`);
|
||||
}
|
||||
|
||||
});
|
||||
timer = setTimeout(() => {
|
||||
try {
|
||||
scriptExecution.kill();
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, this.timeout);
|
||||
});
|
||||
}
|
||||
|
||||
public async executeBufferedCommand(cmd: string, outputChannel?: vscode.OutputChannel): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
if (outputChannel) {
|
||||
outputChannel.appendLine(` > ${cmd}`);
|
||||
}
|
||||
|
||||
let child = childProcess.exec(cmd, {
|
||||
timeout: this.timeout
|
||||
}, (err, stdout) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(stdout);
|
||||
}
|
||||
});
|
||||
|
||||
// Add listeners to print stdout and stderr if an output channel was provided
|
||||
if (outputChannel) {
|
||||
child.stdout.on('data', data => { this.outputDataChunk(data, outputChannel, ' stdout: '); });
|
||||
child.stderr.on('data', data => { this.outputDataChunk(data, outputChannel, ' stderr: '); });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private outputDataChunk(data: string | Buffer, outputChannel: vscode.OutputChannel, header: string): void {
|
||||
data.toString().split(/\r?\n/)
|
||||
.forEach(line => {
|
||||
outputChannel.appendLine(header + line);
|
||||
});
|
||||
}
|
||||
}
|
||||
214
extensions/machine-learning/src/common/queryRunner.ts
Normal file
214
extensions/machine-learning/src/common/queryRunner.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 * as nbExtensionApis from '../typings/notebookServices';
|
||||
import { ApiWrapper } from './apiWrapper';
|
||||
import * as constants from '../common/constants';
|
||||
import * as utils from '../common/utils';
|
||||
|
||||
const maxNumberOfRetries = 2;
|
||||
|
||||
const listPythonPackagesQuery = `
|
||||
Declare @tablevar table(name NVARCHAR(MAX), version NVARCHAR(MAX))
|
||||
insert into @tablevar(name, version)
|
||||
EXEC sp_execute_external_script
|
||||
@language=N'Python',
|
||||
@script=N'import pkg_resources
|
||||
import pandas
|
||||
OutputDataSet = pandas.DataFrame([(d.project_name, d.version) for d in pkg_resources.working_set])'
|
||||
select e.name, version from sys.external_libraries e join @tablevar t on e.name = t.name
|
||||
where [language] = 'PYTHON'
|
||||
`;
|
||||
|
||||
const listRPackagesQuery = `
|
||||
Declare @tablevar table(name NVARCHAR(MAX), version NVARCHAR(MAX))
|
||||
insert into @tablevar(name, version)
|
||||
EXEC sp_execute_external_script
|
||||
@language=N'R',
|
||||
@script=N'
|
||||
OutputDataSet <- as.data.frame(installed.packages()[,c(1,3)])'
|
||||
|
||||
select e.name, version from sys.external_libraries e join @tablevar t on e.name = t.name
|
||||
where [language] = 'R'
|
||||
`;
|
||||
|
||||
const checkMlInstalledQuery = `
|
||||
Declare @tablevar table(name NVARCHAR(MAX), min INT, max INT, config_value bit, run_value bit)
|
||||
insert into @tablevar(name, min, max, config_value, run_value) exec sp_configure
|
||||
|
||||
Declare @external_script_enabled bit
|
||||
SELECT @external_script_enabled=config_value FROM @tablevar WHERE name = 'external scripts enabled'
|
||||
SELECT @external_script_enabled`;
|
||||
|
||||
const checkLanguageInstalledQuery = `
|
||||
|
||||
SELECT is_installed
|
||||
FROM sys.dm_db_external_language_stats s, sys.external_languages l
|
||||
WHERE s.external_language_id = l.external_language_id AND language = '#LANGUAGE#'`;
|
||||
|
||||
const modifyExternalScriptConfigQuery = `
|
||||
|
||||
EXEC sp_configure 'external scripts enabled', #CONFIG_VALUE#;
|
||||
RECONFIGURE WITH OVERRIDE;
|
||||
|
||||
Declare @tablevar table(name NVARCHAR(MAX), min INT, max INT, config_value bit, run_value bit)
|
||||
insert into @tablevar(name, min, max, config_value, run_value) exec sp_configure
|
||||
|
||||
Declare @external_script_enabled bit
|
||||
SELECT @external_script_enabled=config_value FROM @tablevar WHERE name = 'external scripts enabled'
|
||||
SELECT @external_script_enabled`;
|
||||
|
||||
/**
|
||||
* SQL Query runner
|
||||
*/
|
||||
export class QueryRunner {
|
||||
|
||||
constructor(private _apiWrapper: ApiWrapper) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns python packages installed in SQL server instance
|
||||
* @param connection SQL Connection
|
||||
*/
|
||||
public async getPythonPackages(connection: azdata.connection.ConnectionProfile, databaseName: string): Promise<nbExtensionApis.IPackageDetails[]> {
|
||||
return this.getPackages(connection, databaseName, listPythonPackagesQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns python packages installed in SQL server instance
|
||||
* @param connection SQL Connection
|
||||
*/
|
||||
public async getRPackages(connection: azdata.connection.ConnectionProfile, databaseName: string): Promise<nbExtensionApis.IPackageDetails[]> {
|
||||
return this.getPackages(connection, databaseName, listRPackagesQuery);
|
||||
}
|
||||
|
||||
private async getPackages(connection: azdata.connection.ConnectionProfile, databaseName: string, script: string): Promise<nbExtensionApis.IPackageDetails[]> {
|
||||
let packages: nbExtensionApis.IPackageDetails[] = [];
|
||||
let result: azdata.SimpleExecuteResult | undefined = undefined;
|
||||
|
||||
for (let index = 0; index < maxNumberOfRetries; index++) {
|
||||
result = await this.runQuery(connection, utils.getScriptWithDBChange(connection.databaseName, databaseName, script));
|
||||
if (result && result.rowCount > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result && result.rows.length > 0) {
|
||||
packages = result.rows.map(row => {
|
||||
return {
|
||||
name: row[0].displayValue,
|
||||
version: row[1].displayValue
|
||||
};
|
||||
});
|
||||
}
|
||||
return packages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates External Script Config in a SQL server instance
|
||||
* @param connection SQL Connection
|
||||
* @param enable if true the config will be enabled otherwise it will be disabled
|
||||
*/
|
||||
public async updateExternalScriptConfig(connection: azdata.connection.ConnectionProfile, enable: boolean): Promise<void> {
|
||||
let query = modifyExternalScriptConfigQuery;
|
||||
let configValue = enable ? '1' : '0';
|
||||
query = query.replace('#CONFIG_VALUE#', configValue);
|
||||
|
||||
await this.runQuery(connection, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if python installed in the give SQL server instance
|
||||
*/
|
||||
public async isPythonInstalled(connection: azdata.connection.ConnectionProfile): Promise<boolean> {
|
||||
return this.isLanguageInstalled(connection, constants.pythonLanguageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if R installed in the give SQL server instance
|
||||
*/
|
||||
public async isRInstalled(connection: azdata.connection.ConnectionProfile): Promise<boolean> {
|
||||
return this.isLanguageInstalled(connection, constants.rLanguageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if language installed in the give SQL server instance
|
||||
*/
|
||||
private async isLanguageInstalled(connection: azdata.connection.ConnectionProfile, language: string): Promise<boolean> {
|
||||
let result = await this.runQuery(connection, checkLanguageInstalledQuery.replace('#LANGUAGE#', language));
|
||||
let isInstalled = false;
|
||||
if (result && result.rows && result.rows.length > 0) {
|
||||
isInstalled = result.rows[0][0].displayValue === '1';
|
||||
}
|
||||
return isInstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if mls is installed in the give SQL server instance
|
||||
*/
|
||||
public async isMachineLearningServiceEnabled(connection: azdata.connection.ConnectionProfile): Promise<boolean> {
|
||||
let result = await this.runQuery(connection, checkMlInstalledQuery);
|
||||
let isEnabled = false;
|
||||
if (result && result.rows && result.rows.length > 0) {
|
||||
isEnabled = result.rows[0][0].displayValue === '1';
|
||||
}
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public async runQuery(connection: azdata.connection.ConnectionProfile, query: string): Promise<azdata.SimpleExecuteResult | undefined> {
|
||||
let result: azdata.SimpleExecuteResult | undefined = undefined;
|
||||
try {
|
||||
if (connection) {
|
||||
let connectionUri = await this._apiWrapper.getUriForConnection(connection.connectionId);
|
||||
let queryProvider = this._apiWrapper.getProvider<azdata.QueryProvider>(connection.providerId, azdata.DataProviderType.QueryProvider);
|
||||
if (queryProvider) {
|
||||
result = await queryProvider.runQueryAndReturn(connectionUri, query);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query but doesn't fail it is fails
|
||||
* @param connection SQL connection
|
||||
* @param query query to run
|
||||
*/
|
||||
public async safeRunQuery(connection: azdata.connection.ConnectionProfile, query: string): Promise<azdata.SimpleExecuteResult | undefined> {
|
||||
try {
|
||||
return await this.runQuery(connection, query);
|
||||
} catch (error) {
|
||||
//console.log(error);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the query but doesn't fail it is fails
|
||||
* @param connection SQL connection
|
||||
* @param query query to run
|
||||
*/
|
||||
public async runWithDatabaseChange(connection: azdata.connection.ConnectionProfile, query: string, queryDb: string): Promise<azdata.SimpleExecuteResult | undefined> {
|
||||
if (connection) {
|
||||
try {
|
||||
return await this.runQuery(connection, `
|
||||
USE [${utils.doubleEscapeSingleBrackets(queryDb)}]
|
||||
${query}`);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
finally {
|
||||
this.safeRunQuery(connection, `USE [${utils.doubleEscapeSingleBrackets(connection.databaseName || 'master')}]`);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
261
extensions/machine-learning/src/common/utils.ts
Normal file
261
extensions/machine-learning/src/common/utils.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import * as constants from './constants';
|
||||
import { promisify } from 'util';
|
||||
import { ApiWrapper } from './apiWrapper';
|
||||
|
||||
export async function execCommandOnTempFile<T>(content: string, command: (filePath: string) => Promise<T>): Promise<T> {
|
||||
let tempFilePath: string = '';
|
||||
try {
|
||||
tempFilePath = path.join(os.tmpdir(), `ads_ml_temp_${UUID.generateUuid()}`);
|
||||
await fs.promises.writeFile(tempFilePath, content);
|
||||
let result = await command(tempFilePath);
|
||||
return result;
|
||||
}
|
||||
finally {
|
||||
await deleteFile(tempFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a file
|
||||
* @param filePath file path
|
||||
*/
|
||||
export async function deleteFile(filePath: string) {
|
||||
if (filePath) {
|
||||
await fs.promises.unlink(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
export async function readFileInHex(filePath: string): Promise<string> {
|
||||
let buffer = await fs.promises.readFile(filePath);
|
||||
return `0X${buffer.toString('hex')}`;
|
||||
}
|
||||
|
||||
export async function exists(path: string): Promise<boolean> {
|
||||
return promisify(fs.exists)(path);
|
||||
}
|
||||
|
||||
export async function createFolder(dirPath: string): Promise<void> {
|
||||
let folderExists = await exists(dirPath);
|
||||
if (!folderExists) {
|
||||
await fs.promises.mkdir(dirPath);
|
||||
}
|
||||
}
|
||||
|
||||
export function getPythonInstallationLocation(rootFolder: string) {
|
||||
return path.join(rootFolder, 'python');
|
||||
}
|
||||
|
||||
export function getPythonExePath(rootFolder: string): string {
|
||||
return path.join(
|
||||
getPythonInstallationLocation(rootFolder),
|
||||
constants.pythonBundleVersion,
|
||||
process.platform === constants.winPlatform ? 'python.exe' : 'bin/python3');
|
||||
}
|
||||
|
||||
export function getPackageFilePath(rootFolder: string, packageName: string): string {
|
||||
return path.join(
|
||||
rootFolder,
|
||||
constants.rLPackagedFolderName,
|
||||
packageName);
|
||||
}
|
||||
|
||||
export function getRPackagesFolderPath(rootFolder: string): string {
|
||||
return path.join(
|
||||
rootFolder,
|
||||
constants.rLPackagedFolderName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two version strings to see which is greater.
|
||||
* @param first First version string to compare.
|
||||
* @param second Second version string to compare.
|
||||
* @returns 1 if the first version is greater, -1 if it's less, and 0 otherwise.
|
||||
*/
|
||||
export function comparePackageVersions(first: string, second: string): number {
|
||||
let firstVersion = first.split('.').map(numStr => Number.parseInt(numStr));
|
||||
let secondVersion = second.split('.').map(numStr => Number.parseInt(numStr));
|
||||
|
||||
// If versions have different lengths, then append zeroes to the shorter one
|
||||
if (firstVersion.length > secondVersion.length) {
|
||||
let diff = firstVersion.length - secondVersion.length;
|
||||
secondVersion = secondVersion.concat(new Array(diff).fill(0));
|
||||
} else if (secondVersion.length > firstVersion.length) {
|
||||
let diff = secondVersion.length - firstVersion.length;
|
||||
firstVersion = firstVersion.concat(new Array(diff).fill(0));
|
||||
}
|
||||
|
||||
for (let i = 0; i < firstVersion.length; ++i) {
|
||||
if (firstVersion[i] > secondVersion[i]) {
|
||||
return 1;
|
||||
} else if (firstVersion[i] < secondVersion[i]) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function sortPackageVersions(versions: string[], ascending: boolean = true) {
|
||||
return versions.sort((first, second) => {
|
||||
let compareResult = comparePackageVersions(first, second);
|
||||
if (ascending) {
|
||||
return compareResult;
|
||||
} else {
|
||||
return compareResult * -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function isWindows(): boolean {
|
||||
return process.platform === 'win32';
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes all single-quotes (') by prefixing them with another single quote ('')
|
||||
* ' => ''
|
||||
* @param value The string to escape
|
||||
*/
|
||||
export function doubleEscapeSingleQuotes(value: string | undefined): string {
|
||||
return value ? value.replace(/'/g, '\'\'') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes all single-bracket ([]) by replacing them with another bracket quote ([[]])
|
||||
* ' => ''
|
||||
* @param value The string to escape
|
||||
*/
|
||||
export function doubleEscapeSingleBrackets(value: string | undefined): string {
|
||||
return value ? value.replace(/\[/g, '[[').replace(/\]/g, ']]') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs dependencies for the extension
|
||||
*/
|
||||
export async function executeTasks<T>(apiWrapper: ApiWrapper, taskName: string, dependencies: PromiseLike<T>[], parallel: boolean): Promise<T[]> {
|
||||
return new Promise<T[]>((resolve, reject) => {
|
||||
let msgTaskName = taskName;
|
||||
apiWrapper.startBackgroundOperation({
|
||||
displayName: msgTaskName,
|
||||
description: msgTaskName,
|
||||
isCancelable: false,
|
||||
operation: async op => {
|
||||
try {
|
||||
let result: T[] = [];
|
||||
// Install required packages
|
||||
//
|
||||
if (parallel) {
|
||||
result = await Promise.all(dependencies);
|
||||
} else {
|
||||
for (let index = 0; index < dependencies.length; index++) {
|
||||
result.push(await dependencies[index]);
|
||||
}
|
||||
}
|
||||
op.updateStatus(azdata.TaskStatus.Succeeded);
|
||||
resolve(result);
|
||||
} catch (error) {
|
||||
let errorMsg = constants.taskFailedError(taskName, error ? error.message : '');
|
||||
op.updateStatus(azdata.TaskStatus.Failed, errorMsg);
|
||||
reject(errorMsg);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function promptConfirm(message: string, apiWrapper: ApiWrapper): Promise<boolean> {
|
||||
let choices: { [id: string]: boolean } = {};
|
||||
choices[constants.msgYes] = true;
|
||||
choices[constants.msgNo] = false;
|
||||
|
||||
let options = {
|
||||
placeHolder: message
|
||||
};
|
||||
|
||||
let result = await apiWrapper.showQuickPick(Object.keys(choices).map(c => {
|
||||
return {
|
||||
label: c
|
||||
};
|
||||
}), options);
|
||||
if (result === undefined) {
|
||||
throw Error('invalid selection');
|
||||
}
|
||||
|
||||
return choices[result.label] || false;
|
||||
}
|
||||
|
||||
export function makeLinuxPath(filePath: string): string {
|
||||
const parts = filePath.split('\\');
|
||||
return parts.join('/');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param currentDb Wraps the given script with database switch scripts
|
||||
* @param databaseName
|
||||
* @param script
|
||||
*/
|
||||
export function getScriptWithDBChange(currentDb: string, databaseName: string, script: string): string {
|
||||
if (!currentDb) {
|
||||
currentDb = 'master';
|
||||
}
|
||||
let escapedDbName = doubleEscapeSingleBrackets(databaseName);
|
||||
let escapedCurrentDbName = doubleEscapeSingleBrackets(currentDb);
|
||||
return `
|
||||
USE [${escapedDbName}]
|
||||
${script}
|
||||
USE [${escapedCurrentDbName}]
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns full name of model registration table
|
||||
* @param config config
|
||||
*/
|
||||
export function getRegisteredModelsThreePartsName(db: string, table: string, schema: string) {
|
||||
const dbName = doubleEscapeSingleBrackets(db);
|
||||
const schemaName = doubleEscapeSingleBrackets(schema);
|
||||
const tableName = doubleEscapeSingleBrackets(table);
|
||||
return `[${dbName}].[${schemaName}].[${tableName}]`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns full name of model registration table
|
||||
* @param config config object
|
||||
*/
|
||||
export function getRegisteredModelsTwoPartsName(table: string, schema: string) {
|
||||
const schemaName = doubleEscapeSingleBrackets(schema);
|
||||
const tableName = doubleEscapeSingleBrackets(table);
|
||||
return `[${schemaName}].[${tableName}]`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a file using a hex string
|
||||
* @param content file content
|
||||
*/
|
||||
export async function writeFileFromHex(content: string): Promise<string> {
|
||||
content = content.startsWith('0x') || content.startsWith('0X') ? content.substr(2) : content;
|
||||
const tempFilePath = path.join(os.tmpdir(), `ads_ml_temp_${UUID.generateUuid()}`);
|
||||
await fs.promises.writeFile(tempFilePath, Buffer.from(content, 'hex'));
|
||||
return tempFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param filePath Returns file name
|
||||
*/
|
||||
export function getFileName(filePath: string) {
|
||||
if (filePath) {
|
||||
return filePath.replace(/^.*[\\\/]/, '');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user