Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C# run command #488

Merged
merged 13 commits into from
Apr 26, 2019
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -394,4 +394,4 @@
"winston-transport": "^4.3.0",
"xml2js": "^0.4.19"
}
}
}
6 changes: 3 additions & 3 deletions src/lambda/models/samLambdaRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export type SamLambdaRuntime =
'python' |
'nodejs6.10' |
'nodejs8.10' |
'nodejs4.3' |
'nodejs' |
'dotnetcore2.1' |
'dotnetcore2.0' |
Expand All @@ -27,6 +26,7 @@ export type SamLambdaRuntime =
'go' |
'java8' |
'java' |
'ruby' |
'ruby2.5'

export const samLambdaRuntimes: immutable.Set<SamLambdaRuntime> = immutable.Set([
Expand All @@ -36,7 +36,6 @@ export const samLambdaRuntimes: immutable.Set<SamLambdaRuntime> = immutable.Set(
'python',
'nodejs6.10',
'nodejs8.10',
'nodejs4.3',
'nodejs',
'dotnetcore2.1',
'dotnetcore2.0',
Expand All @@ -47,6 +46,7 @@ export const samLambdaRuntimes: immutable.Set<SamLambdaRuntime> = immutable.Set(
'go',
'java8',
'java',
'ruby',
'ruby2.5'
] as SamLambdaRuntime[])

Expand All @@ -68,7 +68,6 @@ export function getFamily(runtime: string | undefined): SamLambdaRuntimeFamily {
return SamLambdaRuntimeFamily.Python
case 'nodejs6.10':
case 'nodejs8.10':
case 'nodejs4.3':
case 'nodejs':
return SamLambdaRuntimeFamily.NodeJS
case 'dotnetcore2.1':
Expand All @@ -84,6 +83,7 @@ export function getFamily(runtime: string | undefined): SamLambdaRuntimeFamily {
case 'java':
return SamLambdaRuntimeFamily.Java
case 'ruby2.5':
case 'ruby':
return SamLambdaRuntimeFamily.Ruby
default:
throw new Error(`Unrecognized runtime: '${runtime}'`)
Expand Down
123 changes: 120 additions & 3 deletions src/shared/codelens/csharpCodeLensProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,33 @@ import * as vscode from 'vscode'

import { LambdaHandlerCandidate } from '../lambdaHandlerSearch'
import { getLogger } from '../logger'
import {
DefaultSamCliProcessInvoker,
DefaultSamCliTaskInvoker
} from '../sam/cli/samCliInvoker'
import { SamCliProcessInvoker, SamCliTaskInvoker } from '../sam/cli/samCliInvokerUtils'
import { SettingsConfiguration } from '../settingsConfiguration'
import { Datum } from '../telemetry/telemetryEvent'
import { TelemetryService } from '../telemetry/telemetryService'
import { registerCommand } from '../telemetry/telemetryUtils'
import { dirnameWithTrailingSlash } from '../utilities/pathUtils'
import { getChannelLogger } from '../utilities/vsCodeUtils'
import {
CodeLensProviderParams,
getInvokeCmdKey,
getMetricDatum,
makeCodeLenses,
} from './codeLensUtils'
import {
executeSamBuild,
getHandlerRelativePath,
getLambdaInfoFromExistingTemplate,
getRelativeFunctionHandler,
getRuntimeForLambda,
invokeLambdaFunction,
LambdaLocalInvokeParams,
makeBuildDir,
makeInputTemplate
} from './localLambdaRunner'

export const CSHARP_LANGUAGE = 'csharp'
Expand All @@ -44,6 +59,11 @@ export interface DotNetLambdaHandlerComponents {
}

export async function initialize({
configuration,
outputChannel: toolkitOutputChannel,
processInvoker = new DefaultSamCliProcessInvoker(),
taskInvoker = new DefaultSamCliTaskInvoker(),
telemetryService
}: CodeLensProviderParams): Promise<void> {
const command = getInvokeCmdKey(CSHARP_LANGUAGE)
registerCommand({
Expand All @@ -52,34 +72,131 @@ export async function initialize({
return await onLocalInvokeCommand({
commandName: command,
lambdaLocalInvokeParams: params,
configuration,
toolkitOutputChannel,
processInvoker,
taskInvoker,
telemetryService
})
},
})
}

/**
* The command that is run when user clicks on Run Local or Debug Local CodeLens
* Accepts object containing the following params:
* @param configuration - SettingsConfiguration (for invokeLambdaFunction)
* @param toolkitOutputChannel - "AWS Toolkit" output channel
* @param commandName - Name of the VS Code Command currently running
* @param lambdaLocalInvokeParams - Information about the Lambda Handler to invoke locally
* @param processInvoker - SAM CLI Process invoker
* @param taskInvoker - SAM CLI Task invoker
* @param telemetryService - Telemetry service for metrics
*/
async function onLocalInvokeCommand({
awschristou marked this conversation as resolved.
Show resolved Hide resolved
configuration,
toolkitOutputChannel,
commandName,
lambdaLocalInvokeParams,
processInvoker,
taskInvoker,
telemetryService
}: {
configuration: SettingsConfiguration
toolkitOutputChannel: vscode.OutputChannel,
commandName: string,
lambdaLocalInvokeParams: LambdaLocalInvokeParams,
processInvoker: SamCliProcessInvoker,
taskInvoker: SamCliTaskInvoker,
telemetryService: TelemetryService
}): Promise<{ datum: Datum }> {

const channelLogger = getChannelLogger(toolkitOutputChannel)
const runtime = await getRuntimeForLambda({
awschristou marked this conversation as resolved.
Show resolved Hide resolved
handlerName: lambdaLocalInvokeParams.handlerName,
templatePath: lambdaLocalInvokeParams.samTemplate.fsPath
})

// TODO : Implement local run/debug in future backlog tasks
vscode.window.showInformationMessage(
`Local ${lambdaLocalInvokeParams.isDebug ? 'debug' : 'run'} support for csharp is currently not implemented.`
bryceitoc9 marked this conversation as resolved.
Show resolved Hide resolved
// Switch over to the output channel so the user has feedback that we're getting things ready
channelLogger.channel.show(true)

channelLogger.info(
'AWS.output.sam.local.start',
'Preparing to run {0} locally...',
lambdaLocalInvokeParams.handlerName
)

try {
if (!lambdaLocalInvokeParams.isDebug) {
const baseBuildDir = await makeBuildDir()
const templateDir = path.dirname(lambdaLocalInvokeParams.samTemplate.fsPath)
const documentUri = lambdaLocalInvokeParams.document.uri
const handlerName = lambdaLocalInvokeParams.handlerName

const handlerFileRelativePath = getHandlerRelativePath({
codeRoot: templateDir,
filePath: documentUri.fsPath
})

const relativeFunctionHandler = getRelativeFunctionHandler({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not obvious to me what "relative function handler means". How about calling it something like "full handler name" or "fully-qualified handler name"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming convention isn't great but it's what was here before. It's actually a bit of a misnomer too--compiled languages don't have any need for a relative pathing to the handler (if you dig into this function, we return the handler unmodified).

I'll see what I can do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So on further analysis, when running the Python handler, args.handlerName === relativeOriginalFunctionHandler and handlerName === relativeFunctionHandler (everything is equal in the case where we aren't debugging since the debug run creates a separate handler file for the SAM run).

That being said, this logic might potentially change going forward as we improve our code detection logic for the Python handler (right now, we only pull in the code directory itself, so any dependencies in different directories might not get picked up on SAM build). Let's keep this around a little longer and determine whether or not we need it when we improve that.

handlerName,
runtime,
handlerFileRelativePath
})

const lambdaInfo = await getLambdaInfoFromExistingTemplate({
workspaceUri: lambdaLocalInvokeParams.workspaceFolder.uri,
relativeOriginalFunctionHandler: relativeFunctionHandler
})

const properties = lambdaInfo ? lambdaInfo.resource.Properties : undefined
const codeDir = properties ? path.join(templateDir, properties.CodeUri) : templateDir

const inputTemplatePath = await makeInputTemplate({
baseBuildDir,
codeDir,
relativeFunctionHandler,
properties,
runtime
})

const samTemplatePath: string = await executeSamBuild({
baseBuildDir,
channelLogger,
codeDir,
inputTemplatePath,
samProcessInvoker: processInvoker,
})

await invokeLambdaFunction({
baseBuildDir,
channelLogger,
configuration,
documentUri,
originalHandlerName: handlerName,
handlerName,
originalSamTemplatePath: inputTemplatePath,
samTemplatePath,
samTaskInvoker: taskInvoker,
telemetryService,
runtime,
isDebug: lambdaLocalInvokeParams.isDebug,

// TODO: Set on debug
debugConfig: undefined,
})
} else {
vscode.window.showInformationMessage(`Local debug for ${runtime} is currently not implemented.`)
}
} catch (err) {
const error = err as Error
channelLogger.error(
'AWS.error.during.sam.local',
'An error occurred trying to run SAM Application locally: {0}',
error
)
}

return getMetricDatum({
isDebug: lambdaLocalInvokeParams.isDebug,
command: commandName,
Expand Down
Loading