| |
| |
| |
| |
|
|
| import * as os from 'os' |
| import * as path from 'path' |
| import { |
| DotNetDebugConfiguration, |
| dotnetDebuggerPath, |
| getCodeRoot, |
| isImageLambdaConfig, |
| } from '../../../lambda/local/debugConfiguration' |
| import { RuntimeFamily } from '../../../lambda/models/samLambdaRuntime' |
| import * as pathutil from '../../../shared/utilities/pathUtils' |
| import { ExtContext } from '../../extensions' |
| import { DefaultSamLocalInvokeCommand, waitForDebuggerMessages } from '../cli/samCliLocalInvoke' |
| import { runLambdaFunction, waitForPort } from '../localLambdaRunner' |
| import { SamLaunchRequestArgs } from './awsSamDebugger' |
| import { ChildProcess } from '../../utilities/processUtils' |
| import { HttpResourceFetcher } from '../../resourcefetcher/httpResourceFetcher' |
| import { getLogger } from '../../logger/logger' |
| import * as vscode from 'vscode' |
| import * as nls from 'vscode-nls' |
| import globals from '../../extensionGlobals' |
| import fs from '../../fs/fs' |
| const localize = nls.loadMessageBundle() |
|
|
| |
| |
| |
| |
| |
| |
| export async function makeCsharpConfig(config: SamLaunchRequestArgs): Promise<SamLaunchRequestArgs> { |
| if (!config.baseBuildDir) { |
| throw Error('invalid state: config.baseBuildDir was not set') |
| } |
| config.codeRoot = (await getCodeRoot(config.workspaceFolder, config))! |
| |
| |
| const originalCodeRoot = config.codeRoot |
| config.codeRoot = getSamProjectDirPathForFile(config.templatePath) |
|
|
| config = { |
| ...config, |
| |
| |
| |
| |
| |
| |
| type: 'coreclr', |
| request: config.noDebug ? 'launch' : 'attach', |
| runtimeFamily: RuntimeFamily.DotNet, |
| } |
|
|
| if (config.sam?.containerBuild) { |
| config.mountWith = 'write' |
| } |
|
|
| if (!config.noDebug) { |
| config = await makeDotnetDebugConfiguration(config, originalCodeRoot) |
| } |
|
|
| return config |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export async function invokeCsharpLambda(ctx: ExtContext, config: SamLaunchRequestArgs): Promise<SamLaunchRequestArgs> { |
| config.samLocalInvokeCommand = new DefaultSamLocalInvokeCommand([waitForDebuggerMessages.DOTNET]) |
| |
| config.onWillAttachDebugger = waitForPort |
| const platformArchitecture = os.arch() |
|
|
| if (!config.noDebug) { |
| if ([config.architecture, platformArchitecture].includes('arm64')) { |
| void vscode.window.showWarningMessage( |
| localize( |
| 'AWS.sam.noArm.dotnet.debug', |
| 'The vsdbg debugger does not currently support the arm64 architecture. Function will run locally without debug.' |
| ) |
| ) |
| getLogger().warn('SAM Invoke: Attempting to debug dotnet on ARM - removing debug flag.') |
| config.noDebug = true |
| } |
| } |
| return await runLambdaFunction(ctx, config, async () => { |
| if (!config.noDebug) { |
| await _installDebugger({ |
| debuggerPath: config.debuggerPath!, |
| }) |
| } |
| }) |
| } |
|
|
| interface InstallDebuggerArgs { |
| debuggerPath: string |
| } |
|
|
| function getDebuggerPath(parentFolder: string): string { |
| return path.resolve(parentFolder, '.vsdbg') |
| } |
|
|
| async function _installDebugger({ debuggerPath }: InstallDebuggerArgs): Promise<void> { |
| await fs.mkdir(debuggerPath) |
|
|
| try { |
| getLogger().info( |
| localize( |
| 'AWS.samcli.local.invoke.debugger.install', |
| 'Installing .NET Core Debugger to {0}...', |
| debuggerPath |
| ) |
| ) |
|
|
| const vsDbgVersion = 'latest' |
| |
| |
| |
| const vsDbgRuntime = 'linux-x64' |
|
|
| const installScriptPath = await downloadInstallScript(debuggerPath) |
|
|
| let installCommand: string |
| let installArgs: string[] |
| if (os.platform() === 'win32') { |
| const windir = process.env['WINDIR'] |
| if (!windir) { |
| throw new Error('Environment variable `WINDIR` not defined') |
| } |
|
|
| installCommand = `${windir}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe` |
| installArgs = [ |
| '-NonInteractive', |
| '-NoProfile', |
| '-WindowStyle', |
| 'Hidden', |
| '-ExecutionPolicy', |
| 'RemoteSigned', |
| '-File', |
| installScriptPath, |
| '-Version', |
| vsDbgVersion, |
| '-RuntimeID', |
| vsDbgRuntime, |
| '-InstallPath', |
| debuggerPath, |
| ] |
| } else { |
| installCommand = installScriptPath |
| installArgs = ['-v', vsDbgVersion, '-r', vsDbgRuntime, '-l', debuggerPath] |
| } |
|
|
| const childProcess = new ChildProcess(installCommand, installArgs) |
|
|
| const install = await childProcess.run({ |
| onStdout: (text: string) => { |
| globals.outputChannel.append(text) |
| }, |
| onStderr: (text: string) => { |
| globals.outputChannel.append(text) |
| }, |
| }) |
|
|
| if (install.exitCode) { |
| throw new Error(`command failed (exit code: ${install.exitCode}): ${installCommand}`) |
| } |
| } catch (err) { |
| getLogger().info( |
| localize( |
| 'AWS.samcli.local.invoke.debugger.install.failed', |
| 'Error installing .NET Core Debugger: {0}', |
| err instanceof Error ? (err as Error).message : String(err) |
| ) |
| ) |
|
|
| throw err |
| } |
| } |
|
|
| async function downloadInstallScript(debuggerPath: string): Promise<string> { |
| let installScriptUrl: string |
| let installScriptPath: string |
| if (os.platform() === 'win32') { |
| installScriptUrl = 'https://aka.ms/getvsdbgps1' |
| installScriptPath = path.join(debuggerPath, 'installVsdbgScript.ps1') |
| } else { |
| installScriptUrl = 'https://aka.ms/getvsdbgsh' |
| installScriptPath = path.join(debuggerPath, 'installVsdbgScript.sh') |
| } |
|
|
| const installScriptFetcher = await new HttpResourceFetcher(installScriptUrl, { showUrl: true }).get() |
| const installScript = await installScriptFetcher?.text() |
| if (!installScript) { |
| throw Error(`Failed to download ${installScriptUrl}`) |
| } |
|
|
| await fs.writeFile(installScriptPath, installScript, 'utf8') |
| await fs.chmod(installScriptPath, 0o700) |
|
|
| return installScriptPath |
| } |
|
|
| function getSamProjectDirPathForFile(filepath: string): string { |
| return pathutil.normalize(path.dirname(filepath)) |
| } |
|
|
| |
| |
| |
| export async function makeDotnetDebugConfiguration( |
| config: SamLaunchRequestArgs, |
| codeUri: string |
| ): Promise<DotNetDebugConfiguration> { |
| if (config.noDebug) { |
| throw Error(`SAM debug: invalid config: ${config.name}`) |
| } |
| const pipeArgs = ['-c', `docker exec -i $(docker ps -q -f publish=${config.debugPort}) \${debuggerCommand}`] |
| config.debuggerPath = pathutil.normalize(getDebuggerPath(codeUri)) |
| await fs.mkdir(config.debuggerPath) |
|
|
| const isImageLambda = await isImageLambdaConfig(config) |
|
|
| if (isImageLambda && !config.noDebug) { |
| config.containerEnvVars = { |
| _AWS_LAMBDA_DOTNET_DEBUGGING: '1', |
| } |
| } |
|
|
| if (os.platform() === 'win32') { |
| |
| codeUri = codeUri.replace(pathutil.driveLetterRegex, (match) => match.toUpperCase()) |
| } |
|
|
| if (isImageLambda) { |
| |
| |
| |
| if (!config.sourceFileMap) { |
| config.sourceFileMap = {} |
| } |
| config.sourceFileMap['/build'] = codeUri |
| } |
|
|
| if (config.lambda?.pathMappings !== undefined) { |
| if (!config.sourceFileMap) { |
| config.sourceFileMap = {} |
| } |
| |
| delete config.sourceFileMap['/build'] |
| for (const mapping of config.lambda.pathMappings) { |
| |
| config.sourceFileMap[mapping.remoteRoot] = mapping.localRoot |
| } |
| } |
|
|
| return { |
| ...config, |
| runtimeFamily: RuntimeFamily.DotNet, |
| request: 'attach', |
| |
| |
| processName: 'dotnet', |
| pipeTransport: { |
| pipeProgram: 'sh', |
| pipeArgs, |
| debuggerPath: dotnetDebuggerPath, |
| pipeCwd: codeUri, |
| }, |
| windows: { |
| pipeTransport: { |
| pipeProgram: 'powershell', |
| pipeArgs, |
| debuggerPath: dotnetDebuggerPath, |
| pipeCwd: codeUri, |
| }, |
| }, |
| } |
| } |
|
|