mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-05 09:35:39 -05:00
Add extension api for calling azdata commands (#11763)
* Add extension api for calling azdata commands * Update typings file name
This commit is contained in:
@@ -9,15 +9,34 @@ import { HttpClient } from './common/httpClient';
|
||||
import * as loc from './localizedConstants';
|
||||
import { executeCommand, executeSudoCommand } from './common/childProcess';
|
||||
import { searchForCmd } from './common/utils';
|
||||
import { AzdataOutput } from './typings/azdata-ext';
|
||||
|
||||
export const azdataHostname = 'https://aka.ms';
|
||||
export const azdataUri = 'azdata-msi';
|
||||
/**
|
||||
* Information about an azdata installation
|
||||
*/
|
||||
export interface IAzdata {
|
||||
|
||||
export interface IAzdataTool {
|
||||
path: string,
|
||||
version: string
|
||||
version: string,
|
||||
/**
|
||||
* Executes azdata with the specified arguments (e.g. --version) and returns the result
|
||||
* @param args The args to pass to azdata
|
||||
* @param parseResult A function used to parse out the raw result into the desired shape
|
||||
*/
|
||||
executeCommand<R>(args: string[], parseResult: (result: any) => R[]): Promise<AzdataOutput<R>>
|
||||
}
|
||||
|
||||
class AzdataTool implements IAzdataTool {
|
||||
constructor(public path: string, public version: string, private _outputChannel: vscode.OutputChannel) { }
|
||||
|
||||
public async executeCommand<R>(args: string[], parseResult: (result: any) => R[]): Promise<AzdataOutput<R>> {
|
||||
const output = JSON.parse((await executeCommand(`"${this.path}"`, args.concat(['--output', 'json']), this._outputChannel)).stdout);
|
||||
return {
|
||||
logs: <string[]>output.log,
|
||||
stdout: <string[]>output.stdout,
|
||||
stderr: <string[]>output.stderr,
|
||||
result: parseResult(output.result)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,10 +44,10 @@ export interface IAzdata {
|
||||
* or encountered an unexpected error.
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
export async function findAzdata(outputChannel: vscode.OutputChannel): Promise<IAzdata> {
|
||||
export async function findAzdata(outputChannel: vscode.OutputChannel): Promise<IAzdataTool> {
|
||||
outputChannel.appendLine(loc.searchingForAzdata);
|
||||
try {
|
||||
let azdata: IAzdata | undefined = undefined;
|
||||
let azdata: IAzdataTool | undefined = undefined;
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
azdata = await findAzdataWin32(outputChannel);
|
||||
@@ -112,7 +131,7 @@ async function installAzdataLinux(outputChannel: vscode.OutputChannel): Promise<
|
||||
* Finds azdata specifically on Windows
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
async function findAzdataWin32(outputChannel: vscode.OutputChannel): Promise<IAzdata> {
|
||||
async function findAzdataWin32(outputChannel: vscode.OutputChannel): Promise<IAzdataTool> {
|
||||
const promise = searchForCmd('azdata.cmd');
|
||||
return findSpecificAzdata(await promise, outputChannel);
|
||||
}
|
||||
@@ -122,12 +141,9 @@ async function findAzdataWin32(outputChannel: vscode.OutputChannel): Promise<IAz
|
||||
* @param path The path to the azdata executable
|
||||
* @param outputChannel Channel used to display diagnostic information
|
||||
*/
|
||||
async function findSpecificAzdata(path: string, outputChannel: vscode.OutputChannel): Promise<IAzdata> {
|
||||
async function findSpecificAzdata(path: string, outputChannel: vscode.OutputChannel): Promise<IAzdataTool> {
|
||||
const versionOutput = await executeCommand(path, ['--version'], outputChannel);
|
||||
return {
|
||||
path: path,
|
||||
version: parseVersion(versionOutput.stdout)
|
||||
};
|
||||
return new AzdataTool(path, parseVersion(versionOutput.stdout), outputChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
39
extensions/azdata/src/common/azdataUtils.ts
Normal file
39
extensions/azdata/src/common/azdataUtils.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { PostgresServerListResult, SqlInstanceListResult } from '../typings/azdata-ext';
|
||||
|
||||
/**
|
||||
* Helper function to parse the raw output from the `azdata postgres server list` command
|
||||
* @param result The raw JSON result array
|
||||
*/
|
||||
export function parsePostgresServerListResult(result: any[]): PostgresServerListResult[] {
|
||||
return result.map(r => {
|
||||
return {
|
||||
id: r['ID'],
|
||||
clusterIP: r['clusterIP'],
|
||||
externalIP: r['externalIP'],
|
||||
mustRestart: r['mustRestart'],
|
||||
name: r['name'],
|
||||
status: r['status']
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to parse the raw output from the `azdata sql instance list` command
|
||||
* @param result The raw JSON result array
|
||||
*/
|
||||
export function parseSqlInstanceListResult(result: any[]): SqlInstanceListResult[] {
|
||||
return result.map(r => {
|
||||
return {
|
||||
clusterEndpoint: r['Cluster Endpoint'],
|
||||
externalEndpoint: r['External Endpoint'],
|
||||
name: r['Name'],
|
||||
status: r['Status'],
|
||||
vCores: r['VCores']
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -3,22 +3,49 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdata from './typings/azdata-ext';
|
||||
import * as vscode from 'vscode';
|
||||
import { findAzdata } from './azdata';
|
||||
import { findAzdata, IAzdataTool } from './azdata';
|
||||
import { parsePostgresServerListResult, parseSqlInstanceListResult } from './common/azdataUtils';
|
||||
|
||||
export async function activate(): Promise<void> {
|
||||
let localAzdata: IAzdataTool | undefined = undefined;
|
||||
|
||||
export async function activate(): Promise<azdata.IExtension> {
|
||||
const outputChannel = vscode.window.createOutputChannel('azdata');
|
||||
await checkForAzdata(outputChannel);
|
||||
localAzdata = await checkForAzdata(outputChannel);
|
||||
return {
|
||||
postgres: {
|
||||
server: {
|
||||
list: async () => {
|
||||
if (!localAzdata) {
|
||||
throw new Error('No azdata');
|
||||
}
|
||||
return localAzdata.executeCommand(['postgres', 'server', 'list'], parsePostgresServerListResult);
|
||||
}
|
||||
}
|
||||
},
|
||||
sql: {
|
||||
instance: {
|
||||
list: async () => {
|
||||
if (!localAzdata) {
|
||||
throw new Error('No azdata');
|
||||
}
|
||||
return localAzdata.executeCommand(['sql', 'instance', 'list'], parseSqlInstanceListResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function checkForAzdata(outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
async function checkForAzdata(outputChannel: vscode.OutputChannel): Promise<IAzdataTool | undefined> {
|
||||
try {
|
||||
await findAzdata(outputChannel);
|
||||
return await findAzdata(outputChannel);
|
||||
} catch (err) {
|
||||
// Don't block on this since we want the extension to finish activating without needing user input.
|
||||
// Calls will be made to handle azdata not being installed
|
||||
promptToInstallAzdata(outputChannel).catch(e => console.log(`Unexpected error prompting to install azdata ${e}`));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function promptToInstallAzdata(_outputChannel: vscode.OutputChannel): Promise<void> {
|
||||
|
||||
51
extensions/azdata/src/typings/azdata-ext.d.ts
vendored
Normal file
51
extensions/azdata/src/typings/azdata-ext.d.ts
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Covers defining what the azdata extension exports to other extensions
|
||||
*
|
||||
* IMPORTANT: THIS IS NOT A HARD DEFINITION unlike vscode; therefore no enums or classes should be defined here
|
||||
* (const enums get evaluated when typescript -> javascript so those are fine)
|
||||
*/
|
||||
export const enum extension {
|
||||
name = 'Microsoft.azdata'
|
||||
}
|
||||
|
||||
export interface SqlInstanceListResult {
|
||||
clusterEndpoint: string,
|
||||
externalEndpoint: string,
|
||||
name: string,
|
||||
status: string,
|
||||
vCores: string
|
||||
}
|
||||
|
||||
export interface PostgresServerListResult {
|
||||
id: string,
|
||||
clusterIP: string,
|
||||
externalIP: string,
|
||||
mustRestart: boolean,
|
||||
name: string,
|
||||
status: string
|
||||
}
|
||||
|
||||
export interface AzdataOutput<R> {
|
||||
logs: string[],
|
||||
result: R[],
|
||||
stderr: string[],
|
||||
stdout: string[]
|
||||
}
|
||||
|
||||
export interface IExtension {
|
||||
postgres: {
|
||||
server: {
|
||||
list(): Promise<AzdataOutput<PostgresServerListResult>>
|
||||
}
|
||||
},
|
||||
sql: {
|
||||
instance: {
|
||||
list(): Promise<AzdataOutput<SqlInstanceListResult>>
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user