From 7ef6775ca071733dce4c50f51a1b2e93299c9afc Mon Sep 17 00:00:00 2001 From: Michael Crane Date: Wed, 12 Jun 2019 13:01:40 -0700 Subject: [PATCH] Refactor remote debugging commands into common library, see Microsoft/vscode-azuretools#522 --- extension.bundle.ts | 2 +- ...ommon.ts => checkForRemoteDebugSupport.ts} | 39 +----- src/commands/remoteDebug/startRemoteDebug.ts | 112 ++---------------- src/commands/remoteDebug/stopRemoteDebug.ts | 22 ++-- src/commands/startSsh.ts | 11 +- 5 files changed, 25 insertions(+), 161 deletions(-) rename src/commands/remoteDebug/{remoteDebugCommon.ts => checkForRemoteDebugSupport.ts} (54%) diff --git a/extension.bundle.ts b/extension.bundle.ts index 6fa76b54b..60f500bb8 100644 --- a/extension.bundle.ts +++ b/extension.bundle.ts @@ -24,4 +24,4 @@ export * from 'vscode-azureextensionui'; export { SubscriptionTreeItem } from './src/explorer/SubscriptionTreeItem'; export { AzureAccountTreeItem } from './src/explorer/AzureAccountTreeItem'; export { getRandomHexString } from './src/utils/randomUtils'; -export { checkForRemoteDebugSupport } from './src/commands/remoteDebug/remoteDebugCommon'; +export { checkForRemoteDebugSupport } from './src/commands/remoteDebug/checkForRemoteDebugSupport'; diff --git a/src/commands/remoteDebug/remoteDebugCommon.ts b/src/commands/remoteDebug/checkForRemoteDebugSupport.ts similarity index 54% rename from src/commands/remoteDebug/remoteDebugCommon.ts rename to src/commands/remoteDebug/checkForRemoteDebugSupport.ts index 95de53162..3e212b31e 100644 --- a/src/commands/remoteDebug/remoteDebugCommon.ts +++ b/src/commands/remoteDebug/checkForRemoteDebugSupport.ts @@ -4,16 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { SiteConfigResource } from 'azure-arm-website/lib/models'; -import * as vscode from 'vscode'; -import { SiteClient } from 'vscode-azureappservice'; -import { callWithTelemetryAndErrorHandling, DialogResponses, IActionContext } from 'vscode-azureextensionui'; -import { ext } from '../../extensionVariables'; - -export const remoteDebugLink: string = 'https://aka.ms/appsvc-remotedebug'; -export function reportMessage(message: string, progress: vscode.Progress<{}>): void { - ext.outputChannel.appendLine(message); - progress.report({ message: message }); -} +import { IActionContext } from 'vscode-azureextensionui'; export function checkForRemoteDebugSupport(siteConfig: SiteConfigResource, context: IActionContext): void { // We read siteConfig.linuxFxVersion to find the image version: @@ -61,31 +52,3 @@ function isNodeVersionSupported(nodeVersion: string): boolean { return (major > 8 || (major === 8 && minor >= 11)); } - -export async function setRemoteDebug(isRemoteDebuggingToBeEnabled: boolean, confirmMessage: string, noopMessage: string | undefined, siteClient: SiteClient, siteConfig: SiteConfigResource, progress?: vscode.Progress<{}>, learnMoreLink?: string): Promise { - if (isRemoteDebuggingToBeEnabled !== siteConfig.remoteDebuggingEnabled) { - const confirmButton: vscode.MessageItem = isRemoteDebuggingToBeEnabled ? { title: 'Enable' } : { title: 'Disable' }; - - // don't have to check input as this handles cancels and learnMore responses - await ext.ui.showWarningMessage(confirmMessage, { modal: true, learnMoreLink }, confirmButton, DialogResponses.cancel); - siteConfig.remoteDebuggingEnabled = isRemoteDebuggingToBeEnabled; - if (progress) { - reportMessage('Updating site configuration to set remote debugging...', progress); - } - - await callWithTelemetryAndErrorHandling('appService.remoteDebugUpdateConfiguration', async (context: IActionContext) => { - context.errorHandling.suppressDisplay = true; - context.errorHandling.rethrow = true; - await siteClient.updateConfiguration(siteConfig); - }); - - if (progress) { - reportMessage('Updating site configuration done...', progress); - } - } else { - // Update not needed - if (noopMessage) { - vscode.window.showWarningMessage(noopMessage); - } - } -} diff --git a/src/commands/remoteDebug/startRemoteDebug.ts b/src/commands/remoteDebug/startRemoteDebug.ts index 14a787614..700f1665e 100644 --- a/src/commands/remoteDebug/startRemoteDebug.ts +++ b/src/commands/remoteDebug/startRemoteDebug.ts @@ -3,120 +3,26 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SiteConfigResource, User } from 'azure-arm-website/lib/models'; -import * as portfinder from 'portfinder'; import * as vscode from 'vscode'; -import { SiteClient, TunnelProxy } from 'vscode-azureappservice'; -import { callWithTelemetryAndErrorHandling, IActionContext } from 'vscode-azureextensionui'; +import * as appservice from 'vscode-azureappservice'; +import { IActionContext } from 'vscode-azureextensionui'; import { SiteTreeItem } from '../../explorer/SiteTreeItem'; import { WebAppTreeItem } from '../../explorer/WebAppTreeItem'; import { ext } from '../../extensionVariables'; -import * as remoteDebug from './remoteDebugCommon'; - -let isRemoteDebugging = false; +import { checkForRemoteDebugSupport } from './checkForRemoteDebugSupport'; export async function startRemoteDebug(context: IActionContext, node?: SiteTreeItem): Promise { - if (isRemoteDebugging) { - throw new Error('Azure Remote Debugging is currently starting or already started.'); - } - - isRemoteDebugging = true; - try { - await startRemoteDebugInternal(context, node); - } catch (error) { - isRemoteDebugging = false; - throw error; - } -} - -async function startRemoteDebugInternal(context: IActionContext, node?: SiteTreeItem): Promise { if (!node) { node = await ext.tree.showTreeItemPicker(WebAppTreeItem.contextValue, context); } - const siteClient: SiteClient = node.root.client; - - await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>): Promise => { - remoteDebug.reportMessage('Fetching site configuration...', progress); - const siteConfig: SiteConfigResource = await siteClient.getSiteConfig(); - - remoteDebug.checkForRemoteDebugSupport(siteConfig, context); - const debugConfig: vscode.DebugConfiguration = await getDebugConfiguration(); - // tslint:disable-next-line:no-unsafe-any - const localHostPortNumber: number = debugConfig.port; - - remoteDebug.reportMessage('Checking app settings...', progress); - - const confirmEnableMessage: string = 'The app configuration will be updated to enable remote debugging and restarted. Would you like to continue?'; - await remoteDebug.setRemoteDebug(true, confirmEnableMessage, undefined, siteClient, siteConfig, progress, remoteDebug.remoteDebugLink); - - remoteDebug.reportMessage('Starting tunnel proxy...', progress); - const publishCredential: User = await siteClient.getWebAppPublishCredential(); - const tunnelProxy: TunnelProxy = new TunnelProxy(localHostPortNumber, siteClient, publishCredential); - await callWithTelemetryAndErrorHandling('appService.remoteDebugStartProxy', async (startContext: IActionContext) => { - startContext.errorHandling.suppressDisplay = true; - startContext.errorHandling.rethrow = true; - await tunnelProxy.startProxy(); - }); - - remoteDebug.reportMessage('Attaching debugger...', progress); - - await callWithTelemetryAndErrorHandling('appService.remoteDebugAttach', async (attachContext: IActionContext) => { - attachContext.errorHandling.suppressDisplay = true; - attachContext.errorHandling.rethrow = true; - await vscode.debug.startDebugging(undefined, debugConfig); - }); - - remoteDebug.reportMessage('Attached!', progress); - - const terminateDebugListener: vscode.Disposable = vscode.debug.onDidTerminateDebugSession(async (event: vscode.DebugSession) => { - if (event.name === debugConfig.name) { - isRemoteDebugging = false; - - if (tunnelProxy !== undefined) { - tunnelProxy.dispose(); - } - terminateDebugListener.dispose(); - - const confirmDisableMessage: string = 'Leaving the app in debugging mode may cause performance issues. Would you like to disable debugging for this app? The app will be restarted.'; - await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (innerProgress: vscode.Progress<{}>): Promise => { - await remoteDebug.setRemoteDebug(false, confirmDisableMessage, undefined, siteClient, siteConfig, innerProgress, remoteDebug.remoteDebugLink); - }); - } - }); + const siteClient = node.root.client; + const siteConfig = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async progress => { + appservice.reportMessage('Fetching site configuration...', progress); + return await siteClient.getSiteConfig(); }); -} - -async function getDebugConfiguration(): Promise { - const sessionId: string = Date.now().toString(); - const portNumber: number = await portfinder.getPortPromise(); - // So far only node is supported - const config: vscode.DebugConfiguration = { - // return { - name: sessionId, - type: 'node', - protocol: 'inspector', - request: 'attach', - address: 'localhost', - port: portNumber - }; - - // Try to map workspace folder source files to the remote instance - if (vscode.workspace.workspaceFolders) { - if (vscode.workspace.workspaceFolders.length === 1) { - config.localRoot = vscode.workspace.workspaceFolders[0].uri.fsPath; - config.remoteRoot = '/home/site/wwwroot'; - } else { - // In this case we don't know which folder to use. Show a warning and proceed. - // In the future we should allow users to choose a workspace folder to map sources from. - // tslint:disable-next-line:no-floating-promises - ext.ui.showWarningMessage('Unable to bind breakpoints from workspace when multiple folders are open. Use "loaded scripts" instead.'); - } - } else { - // vscode will throw an error if you try to start debugging without any workspace folder open - throw new Error("Please open a workspace folder before attaching a debugger."); - } + checkForRemoteDebugSupport(siteConfig, context); - return config; + await appservice.startRemoteDebug(siteClient, siteConfig); } diff --git a/src/commands/remoteDebug/stopRemoteDebug.ts b/src/commands/remoteDebug/stopRemoteDebug.ts index 1a39b1251..a157559b4 100644 --- a/src/commands/remoteDebug/stopRemoteDebug.ts +++ b/src/commands/remoteDebug/stopRemoteDebug.ts @@ -3,30 +3,26 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { SiteConfigResource } from 'azure-arm-website/lib/models'; import * as vscode from 'vscode'; -import { SiteClient } from 'vscode-azureappservice'; +import * as appservice from 'vscode-azureappservice'; import { IActionContext } from 'vscode-azureextensionui'; import { SiteTreeItem } from '../../explorer/SiteTreeItem'; import { WebAppTreeItem } from '../../explorer/WebAppTreeItem'; import { ext } from '../../extensionVariables'; -import * as remoteDebug from './remoteDebugCommon'; +import { checkForRemoteDebugSupport } from './checkForRemoteDebugSupport'; export async function stopRemoteDebug(context: IActionContext, node?: SiteTreeItem): Promise { if (!node) { node = await ext.tree.showTreeItemPicker(WebAppTreeItem.contextValue, context); } - const siteClient: SiteClient = node.root.client; - const confirmMessage: string = 'The app configuration will be updated to disable remote debugging and restarted. Would you like to continue?'; - const noopMessage: string = 'The app is not configured for debugging.'; - - await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>): Promise => { - remoteDebug.reportMessage('Fetching site configuration...', progress); - const siteConfig: SiteConfigResource = await siteClient.getSiteConfig(); + const siteClient = node.root.client; + const siteConfig = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async progress => { + appservice.reportMessage('Fetching site configuration...', progress); + return await siteClient.getSiteConfig(); + }); - remoteDebug.checkForRemoteDebugSupport(siteConfig, context); + checkForRemoteDebugSupport(siteConfig, context); - await remoteDebug.setRemoteDebug(false, confirmMessage, noopMessage, siteClient, siteConfig, progress, remoteDebug.remoteDebugLink); - }); + await appservice.startRemoteDebug(siteClient, siteConfig); } diff --git a/src/commands/startSsh.ts b/src/commands/startSsh.ts index 7255e2779..0862f099e 100644 --- a/src/commands/startSsh.ts +++ b/src/commands/startSsh.ts @@ -6,13 +6,12 @@ import { SiteConfigResource, User } from 'azure-arm-website/lib/models'; import * as portfinder from 'portfinder'; import * as vscode from 'vscode'; -import { SiteClient, TunnelProxy } from 'vscode-azureappservice'; +import { reportMessage, setRemoteDebug, SiteClient, TunnelProxy } from 'vscode-azureappservice'; import { IActionContext } from 'vscode-azureextensionui'; import { SiteTreeItem } from '../explorer/SiteTreeItem'; import { WebAppTreeItem } from '../explorer/WebAppTreeItem'; import { ext } from '../extensionVariables'; import { delay } from '../utils/delay'; -import * as remoteDebug from './remoteDebug/remoteDebugCommon'; export type sshTerminal = { starting: boolean, @@ -55,14 +54,14 @@ async function startSshInternal(node: SiteTreeItem): Promise { await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification }, async (progress: vscode.Progress<{}>): Promise => { - remoteDebug.reportMessage('Checking app settings...', progress); + reportMessage('Checking app settings...', progress); const confirmDisableMessage: string = 'Remote debugging must be disabled in order to SSH. This will restart the app.'; const siteConfig: SiteConfigResource = await siteClient.getSiteConfig(); // remote debugging has to be disabled in order to tunnel to the 2222 port - await remoteDebug.setRemoteDebug(false, confirmDisableMessage, undefined, siteClient, siteConfig, progress); + await setRemoteDebug(false, confirmDisableMessage, undefined, siteClient, siteConfig, progress); - remoteDebug.reportMessage('Initializing SSH...', progress); + reportMessage('Initializing SSH...', progress); const publishCredential: User = await siteClient.getWebAppPublishCredential(); const localHostPortNumber: number = await portfinder.getPortPromise(); // should always be an unbound port @@ -70,7 +69,7 @@ async function startSshInternal(node: SiteTreeItem): Promise { await tunnelProxy.startProxy(); - remoteDebug.reportMessage('Connecting to SSH...', progress); + reportMessage('Connecting to SSH...', progress); await connectToTunnelProxy(node, tunnelProxy, localHostPortNumber); }); }