| |
| |
| |
| |
|
|
| import { Runtime } from '@aws-sdk/client-lambda' |
| import * as os from 'os' |
| import * as path from 'path' |
| import { |
| isImageLambdaConfig, |
| PythonDebugConfiguration, |
| PythonPathMapping, |
| } from '../../../lambda/local/debugConfiguration' |
| import { RuntimeFamily } from '../../../lambda/models/samLambdaRuntime' |
| import globals from '../../extensionGlobals' |
| import { ExtContext } from '../../extensions' |
| import { fileExists, readFileAsString } from '../../filesystemUtilities' |
| import { getLogger } from '../../logger/logger' |
| import * as pathutil from '../../utilities/pathUtils' |
| import { getLocalRootVariants } from '../../utilities/pathUtils' |
| import { DefaultSamLocalInvokeCommand, waitForDebuggerMessages } from '../cli/samCliLocalInvoke' |
| import { runLambdaFunction } from '../localLambdaRunner' |
| import { SamLaunchRequestArgs } from './awsSamDebugger' |
| import fs from '../../fs/fs' |
|
|
| |
| const debugpyWrapperPath = '/tmp/lambci_debug_files/py_debug_wrapper.py' |
|
|
| |
| export async function getSamProjectDirPathForFile(filepath: string): Promise<string> { |
| return path.dirname(filepath) |
| } |
|
|
| |
| async function makePythonDebugManifest(params: { |
| isImageLambda: boolean |
| samProjectCodeRoot: string |
| outputDir: string |
| }): Promise<string | undefined> { |
| let manifestText = '' |
| const manfestPath = path.join(params.samProjectCodeRoot, 'requirements.txt') |
| |
| const debugManifestPath = params.isImageLambda ? manfestPath : path.join(params.outputDir, 'debug-requirements.txt') |
| if (await fileExists(manfestPath)) { |
| manifestText = await readFileAsString(manfestPath) |
| } |
| getLogger().debug(`pythonCodeLensProvider.makePythonDebugManifest params: %O`, params) |
|
|
| |
| if (!manifestText.includes('debugpy')) { |
| manifestText += `${os.EOL}debugpy>=1.0,<2` |
| await fs.writeFile(debugManifestPath, manifestText) |
|
|
| return debugManifestPath |
| } |
| |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export async function makePythonDebugConfig(config: SamLaunchRequestArgs): Promise<PythonDebugConfiguration> { |
| if (!config.baseBuildDir) { |
| throw Error('invalid state: config.baseBuildDir was not set') |
| } |
| if (!config.codeRoot) { |
| |
| |
| config.codeRoot = await getSamProjectDirPathForFile(config?.templatePath ?? config.documentUri!.fsPath) |
| if (!config.codeRoot) { |
| |
| throw Error('missing launch.json, template.yaml, and failed to discover project root') |
| } |
| } |
| config.codeRoot = pathutil.normalize(config.codeRoot) |
|
|
| let manifestPath: string | undefined |
| if (!config.noDebug) { |
| const isImageLambda = await isImageLambdaConfig(config) |
|
|
| |
| config.debuggerPath = globals.context.asAbsolutePath(path.join('resources', 'debugger')) |
| |
| |
| const debugArgs = `${debugpyWrapperPath} --listen 0.0.0.0:${config.debugPort} --wait-for-client --log-to-stderr` |
| if (isImageLambda) { |
| const params = getPythonExeAndBootstrap(config.runtime) |
| config.debugArgs = [`${params.python} ${debugArgs} ${params.bootstrap}`] |
| } else { |
| config.debugArgs = [debugArgs] |
| } |
|
|
| manifestPath = await makePythonDebugManifest({ |
| isImageLambda: isImageLambda, |
| samProjectCodeRoot: config.codeRoot, |
| outputDir: config.baseBuildDir, |
| }) |
| } |
|
|
| let pathMappings: PythonPathMapping[] |
| if (config.lambda?.pathMappings !== undefined) { |
| pathMappings = config.lambda.pathMappings |
| } else { |
| pathMappings = getLocalRootVariants(config.codeRoot).map<PythonPathMapping>((variant) => { |
| return { |
| localRoot: variant, |
| remoteRoot: '/var/task', |
| } |
| }) |
| } |
|
|
| |
| if (!config.noDebug && getLogger().logLevelEnabled('debug')) { |
| config.debugArgs![0] += ' --debug' |
| } |
|
|
| return { |
| ...config, |
| type: 'python', |
| request: config.noDebug ? 'launch' : 'attach', |
| runtimeFamily: RuntimeFamily.Python, |
|
|
| |
| |
| |
| manifestPath: manifestPath, |
| port: config.debugPort ?? -1, |
| host: 'localhost', |
| pathMappings, |
| |
| |
| redirectOutput: false, |
| } |
| } |
|
|
| |
| |
| |
| export async function invokePythonLambda( |
| ctx: ExtContext, |
| config: PythonDebugConfiguration |
| ): Promise<PythonDebugConfiguration> { |
| config.samLocalInvokeCommand = new DefaultSamLocalInvokeCommand([waitForDebuggerMessages.PYTHON]) |
|
|
| config.onWillAttachDebugger = undefined |
| const c = (await runLambdaFunction(ctx, config, async () => {})) as PythonDebugConfiguration |
| return c |
| } |
|
|
| function getPythonExeAndBootstrap(runtime: Runtime) { |
| |
| |
| switch (runtime) { |
| case 'python3.9': |
| case 'python3.10': |
| case 'python3.11': |
| case 'python3.12': |
| case 'python3.13' as Runtime: |
| case 'python3.14' as Runtime: |
| return { python: `/var/lang/bin/${runtime}`, bootstrap: '/var/runtime/bootstrap.py' } |
| default: |
| throw new Error(`Python SAM debug logic ran for invalid Python runtime: ${runtime}`) |
| } |
| } |
|
|