Skip to content

Commit cc7ad02

Browse files
authored
filewatcher: template watcher lazy-loads if enableCodeLenses is off (#3938)
## Problem The template file watcher always ran regardless of SAM hint setting ## Solution The template file watcher now loads on demand. This appears to work even when toggling from off to on (codelenses appear on the template file) * ~~This may hit the startup function multiple times? Will do some more testing~~ should be resolved with 0b1df9d * Confirmed SAM debug works, when coming from startup with codelenses disabled * Confirmed the registry builds when codelenses are enabled
1 parent efabb7e commit cc7ad02

33 files changed

+306
-253
lines changed

src/lambda/commands/createNewSamApp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ export async function createNewSamApplication(
271271
// Race condition where SAM app is created but template doesn't register in time.
272272
// Poll for 5 seconds, otherwise direct user to codelens.
273273
const isTemplateRegistered = await waitUntil(
274-
async () => globals.templateRegistry.getRegisteredItem(templateUri),
274+
async () => (await globals.templateRegistry).getRegisteredItem(templateUri),
275275
{
276276
timeout: 5000,
277277
interval: 500,

src/lambda/commands/downloadLambda.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,8 @@ async function addLaunchConfigEntry(
206206
)
207207

208208
const launchConfig = new LaunchConfiguration(vscode.Uri.file(lambdaLocation))
209-
if (
210-
!getReferencedHandlerPaths(launchConfig).has(
211-
pathutils.normalize(path.join(path.dirname(lambdaLocation), handler))
212-
)
213-
) {
209+
const refPaths = await getReferencedHandlerPaths(launchConfig)
210+
if (!refPaths.has(pathutils.normalize(path.join(path.dirname(lambdaLocation), handler)))) {
214211
await launchConfig.addDebugConfiguration(samDebugConfig)
215212
}
216213
}

src/lambda/local/debugConfiguration.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ export interface PipeTransport {
100100
* - For "code" configs this is the `projectRoot` field.
101101
* - For "template" configs this is the `CodeUri` field in the template.
102102
*/
103-
export function getCodeRoot(
103+
export async function getCodeRoot(
104104
folder: vscode.WorkspaceFolder | undefined,
105105
config: AwsSamDebuggerConfiguration
106-
): string | undefined {
106+
): Promise<string | undefined> {
107107
switch (config.invokeTarget.target) {
108108
case 'code': {
109109
const codeInvoke = config.invokeTarget as CodeTargetProperties
@@ -112,11 +112,11 @@ export function getCodeRoot(
112112
case 'api':
113113
case 'template': {
114114
const templateInvoke = config.invokeTarget as TemplateTargetProperties
115-
const template = getTemplate(folder, config)
115+
const template = await getTemplate(folder, config)
116116
if (!template) {
117117
return undefined
118118
}
119-
const templateResource = getTemplateResource(folder, config)
119+
const templateResource = await getTemplateResource(folder, config)
120120
if (!templateResource?.Properties) {
121121
return undefined
122122
}
@@ -142,22 +142,22 @@ export function getCodeRoot(
142142
/**
143143
* Gets the lambda handler name specified in the given config.
144144
*/
145-
export function getHandlerName(
145+
export async function getHandlerName(
146146
folder: vscode.WorkspaceFolder | undefined,
147147
config: AwsSamDebuggerConfiguration
148-
): string {
148+
): Promise<string> {
149149
switch (config.invokeTarget.target) {
150150
case 'code': {
151151
const codeInvoke = config.invokeTarget as CodeTargetProperties
152152
return codeInvoke.lambdaHandler
153153
}
154154
case 'api':
155155
case 'template': {
156-
const template = getTemplate(folder, config)
156+
const template = await getTemplate(folder, config)
157157
if (!template) {
158158
return ''
159159
}
160-
const templateResource = getTemplateResource(folder, config)
160+
const templateResource = await getTemplateResource(folder, config)
161161
if (CloudFormation.isImageLambdaResource(templateResource?.Properties)) {
162162
return config.invokeTarget.logicalId
163163
}
@@ -184,32 +184,32 @@ export function getHandlerName(
184184
}
185185

186186
/** Gets a template object from the given config. */
187-
export function getTemplate(
187+
export async function getTemplate(
188188
folder: vscode.WorkspaceFolder | undefined,
189189
config: AwsSamDebuggerConfiguration
190-
): CloudFormation.Template | undefined {
190+
): Promise<CloudFormation.Template | undefined> {
191191
if (!['api', 'template'].includes(config.invokeTarget.target)) {
192192
return undefined
193193
}
194194
const templateInvoke = config.invokeTarget as TemplateTargetProperties
195195
const fullPath = tryGetAbsolutePath(folder, templateInvoke.templatePath)
196-
const cfnTemplate = globals.templateRegistry.getRegisteredItem(fullPath)?.item
196+
const cfnTemplate = (await globals.templateRegistry).getRegisteredItem(fullPath)?.item
197197
return cfnTemplate
198198
}
199199

200200
/**
201201
* Gets the template resources object specified by the `logicalId`
202202
* field (if the config has `target=template` or `target=api`).
203203
*/
204-
export function getTemplateResource(
204+
export async function getTemplateResource(
205205
folder: vscode.WorkspaceFolder | undefined,
206206
config: AwsSamDebuggerConfiguration
207-
): CloudFormation.Resource | undefined {
207+
): Promise<CloudFormation.Resource | undefined> {
208208
if (!['api', 'template'].includes(config.invokeTarget.target)) {
209209
return undefined
210210
}
211211
const templateInvoke = config.invokeTarget as TemplateTargetProperties
212-
const cfnTemplate = getTemplate(folder, config)
212+
const cfnTemplate = await getTemplate(folder, config)
213213
if (!cfnTemplate) {
214214
throw Error(`template not found (not registered?): ${templateInvoke.templatePath}`)
215215
}
@@ -231,8 +231,8 @@ export function getTemplateResource(
231231
*
232232
* Intended for use only by the language-specific `makeConfig` functions.
233233
*/
234-
export function isImageLambdaConfig(config: SamLaunchRequestArgs): boolean {
235-
const templateResource = getTemplateResource(config.workspaceFolder, config)
234+
export async function isImageLambdaConfig(config: SamLaunchRequestArgs): Promise<boolean> {
235+
const templateResource = await getTemplateResource(config.workspaceFolder, config)
236236

237237
return CloudFormation.isImageLambdaResource(templateResource?.Properties)
238238
}

src/lambda/vue/configEditor/samInvokeBackend.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export class SamInvokeWebview extends VueWebview {
9494
}
9595
const uri = workspaceFolder.uri
9696
const launchConfig = new LaunchConfiguration(uri)
97-
const pickerItems = getLaunchConfigQuickPickItems(launchConfig, uri)
97+
const pickerItems = await getLaunchConfigQuickPickItems(launchConfig, uri)
9898
if (pickerItems.length === 0) {
9999
pickerItems.push({
100100
index: -1,
@@ -161,7 +161,7 @@ export class SamInvokeWebview extends VueWebview {
161161
public async getTemplate() {
162162
const items: (vscode.QuickPickItem & { templatePath: string })[] = []
163163
const noTemplate = 'NOTEMPLATEFOUND'
164-
for (const template of globals.templateRegistry.registeredItems) {
164+
for (const template of (await globals.templateRegistry).registeredItems) {
165165
const resources = template.item.Resources
166166
if (resources) {
167167
for (const resource of Object.keys(resources)) {
@@ -227,6 +227,7 @@ export class SamInvokeWebview extends VueWebview {
227227
return
228228
}
229229
const launchConfig = new LaunchConfiguration(uri)
230+
const launchConfigItems = await getLaunchConfigQuickPickItems(launchConfig, uri)
230231
const pickerItems = [
231232
{
232233
label: addCodiconToString(
@@ -236,7 +237,7 @@ export class SamInvokeWebview extends VueWebview {
236237
index: -1,
237238
alwaysShow: true,
238239
},
239-
...getLaunchConfigQuickPickItems(launchConfig, uri),
240+
...launchConfigItems,
240241
]
241242

242243
const qp = picker.createQuickPick({
@@ -343,17 +344,24 @@ function getUriFromLaunchConfig(config: AwsSamDebuggerConfiguration): vscode.Uri
343344
return undefined
344345
}
345346

346-
function getLaunchConfigQuickPickItems(launchConfig: LaunchConfiguration, uri: vscode.Uri): LaunchConfigPickItem[] {
347+
async function getLaunchConfigQuickPickItems(
348+
launchConfig: LaunchConfiguration,
349+
uri: vscode.Uri
350+
): Promise<LaunchConfigPickItem[]> {
347351
const existingConfigs = launchConfig.getDebugConfigurations()
348352
const samValidator = new DefaultAwsSamDebugConfigurationValidator(vscode.workspace.getWorkspaceFolder(uri))
353+
const registry = await globals.templateRegistry
349354
return existingConfigs
350355
.map((val, index) => {
351356
return {
352357
config: val,
353358
index,
354359
}
355360
})
356-
.filter(o => samValidator.validate(o.config as any as AwsSamDebuggerConfiguration, true)?.isValid)
361+
.filter(o => {
362+
const res = samValidator.validate(o.config as any as AwsSamDebuggerConfiguration, registry, true)
363+
return res?.isValid
364+
})
357365
.map(val => {
358366
return {
359367
index: val.index,

src/lambda/wizards/samDeployWizard.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export class DefaultSamDeployWizardContext implements SamDeployWizardContext {
211211
}
212212

213213
public async determineIfTemplateHasImages(templatePath: vscode.Uri): Promise<boolean> {
214-
const template = globals.templateRegistry.getRegisteredItem(templatePath.fsPath)
214+
const template = (await globals.templateRegistry).getRegisteredItem(templatePath.fsPath)
215215
const resources = template?.item?.Resources
216216
if (resources === undefined) {
217217
return false
@@ -933,7 +933,7 @@ function validateStackName(value: string): string | undefined {
933933
}
934934

935935
async function getTemplateChoices(...workspaceFolders: vscode.Uri[]): Promise<SamTemplateQuickPickItem[]> {
936-
const templateUris = globals.templateRegistry.registeredItems.map(o => vscode.Uri.file(o.path))
936+
const templateUris = (await globals.templateRegistry).registeredItems.map(o => vscode.Uri.file(o.path))
937937
const uriToLabel: Map<vscode.Uri, string> = new Map<vscode.Uri, string>()
938938
const labelCounts: Map<string, number> = new Map()
939939

src/shared/awsFiletypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function activate(): void {
6767
vscode.workspace.onDidOpenTextDocument(async (doc: vscode.TextDocument) => {
6868
const isAwsFileExt = isAwsFiletype(doc)
6969
const isSchemaHandled = globals.schemaService.isMapped(doc.uri)
70-
const isCfnTemplate = !!globals.templateRegistry.registeredItems.find(
70+
const isCfnTemplate = !!(await globals.templateRegistry).registeredItems.find(
7171
t => pathutil.normalize(t.path) === pathutil.normalize(doc.fileName)
7272
)
7373
if (!isAwsFileExt && !isSchemaHandled && !isCfnTemplate) {

src/shared/cloudformation/activation.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55

66
import * as vscode from 'vscode'
77
import { getLogger } from '../logger'
8-
import { localize } from '../utilities/vsCodeUtils'
8+
import { isToolkitActive, localize } from '../utilities/vsCodeUtils'
99

1010
import { AsyncCloudFormationTemplateRegistry, CloudFormationTemplateRegistry } from '../fs/templateRegistry'
1111
import { getIdeProperties } from '../extensionUtilities'
1212
import { NoopWatcher } from '../fs/watchedFiles'
1313
import { createStarterTemplateFile } from './cloudformation'
1414
import { Commands } from '../vscode/commands2'
1515
import globals from '../extensionGlobals'
16+
import { SamCliSettings } from '../sam/cli/samCliSettings'
1617

1718
export const templateFileGlobPattern = '**/*.{yaml,yml}'
1819

@@ -48,7 +49,7 @@ export async function activate(extensionContext: vscode.ExtensionContext): Promi
4849
getLogger().error('Failed to activate template registry: %s', e)
4950
// This prevents us from breaking for any reason later if it fails to load. Since
5051
// Noop watcher is always empty, we will get back empty arrays with no issues.
51-
globals.templateRegistry = new NoopWatcher() as unknown as CloudFormationTemplateRegistry
52+
globals.templateRegistry = (async () => new NoopWatcher() as unknown as CloudFormationTemplateRegistry)()
5253
}
5354
// If setting it up worked, add it to subscriptions so it is cleaned up at exit
5455
extensionContext.subscriptions.push(
@@ -71,6 +72,8 @@ function setTemplateRegistryInGlobals(registry: CloudFormationTemplateRegistry)
7172
await registry.addExcludedPattern(templateFileExcludePattern)
7273
await registry.addWatchPatterns([templateFileGlobPattern])
7374
await registry.watchUntitledFiles()
75+
76+
return registry
7477
}
7578

7679
const asyncRegistry = new AsyncCloudFormationTemplateRegistry(registry, registrySetupFunc)
@@ -79,15 +82,21 @@ function setTemplateRegistryInGlobals(registry: CloudFormationTemplateRegistry)
7982
set(newInstance: CloudFormationTemplateRegistry) {
8083
this.cfnInstance = newInstance
8184
},
82-
get() {
85+
async get() {
8386
// This condition handles testing scenarios where we may have
8487
// already set a mock object before activation.
8588
// Though in prod nothing should be calling this 'set' function.
8689
if (this.cfnInstance) {
8790
return this.cfnInstance
8891
}
8992

90-
return asyncRegistry.getInstance()
93+
// prevent eager load if codelenses are off
94+
const config = SamCliSettings.instance
95+
if (config.get('enableCodeLenses', false) || isToolkitActive()) {
96+
return await asyncRegistry.getInstance()
97+
}
98+
99+
return NoopWatcher
91100
},
92101
})
93102
}

src/shared/codelens/codeLensUtils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import * as goCodelens from './goCodeLensProvider'
2525
import { VSCODE_EXTENSION_ID } from '../extensions'
2626
import { getIdeProperties } from '../extensionUtilities'
2727
import { SamCliSettings } from '../sam/cli/samCliSettings'
28+
import globals from '../extensionGlobals'
2829

2930
export type Language = 'python' | 'javascript' | 'csharp' | 'go' | 'java' | 'typescript'
3031

@@ -59,7 +60,12 @@ export async function makeCodeLenses({
5960
)
6061

6162
try {
62-
const associatedResources = getResourcesForHandler(handler.filename, handler.handlerName)
63+
const registry = await globals.templateRegistry
64+
const associatedResources = getResourcesForHandler(
65+
handler.filename,
66+
handler.handlerName,
67+
registry.registeredItems
68+
)
6369
const templateConfigs: AddSamDebugConfigurationInput[] = []
6470

6571
if (associatedResources.length > 0) {

src/shared/codelens/samTemplateCodeLensProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ export class SamTemplateCodeLensProvider implements vscode.CodeLensProvider {
3131
}
3232

3333
// User already has launch configs for:
34-
const mappedApiConfigs = Array.from(getConfigsMappedToTemplates(launchConfig, 'api'))
35-
const mappedFunConfigs = Array.from(getConfigsMappedToTemplates(launchConfig, 'template'))
34+
const mappedApiConfigs = Array.from(await getConfigsMappedToTemplates(launchConfig, 'api'))
35+
const mappedFunConfigs = Array.from(await getConfigsMappedToTemplates(launchConfig, 'template'))
3636

3737
const unmappedApis = apiResources.filter(
3838
r =>

src/shared/debug/launchConfiguration.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { getLogger } from '../logger'
2626
import { makeFailedWriteMessage, showViewLogsMessage } from '../utilities/messages'
2727
import { launchConfigDocUrl } from '../constants'
2828
import { openUrl } from '../utilities/vsCodeUtils'
29+
import globals from '../extensionGlobals'
2930

3031
const localize = nls.loadMessageBundle()
3132

@@ -68,11 +69,12 @@ export class LaunchConfiguration {
6869
/**
6970
* Returns all valid Sam Debug Configurations.
7071
*/
71-
public getSamDebugConfigurations(): AwsSamDebuggerConfiguration[] {
72+
public async getSamDebugConfigurations(): Promise<AwsSamDebuggerConfiguration[]> {
7273
const configs = this.getDebugConfigurations().filter(o =>
7374
isAwsSamDebugConfiguration(o)
7475
) as AwsSamDebuggerConfiguration[]
75-
return configs.filter(o => this.samValidator.validate(o)?.isValid)
76+
const registry = await globals.templateRegistry
77+
return configs.filter(o => this.samValidator.validate(o, registry)?.isValid)
7678
}
7779

7880
/**
@@ -127,8 +129,9 @@ class DefaultDebugConfigSource implements DebugConfigurationSource {
127129
}
128130
}
129131

130-
function getSamCodeTargets(launchConfig: LaunchConfiguration): CodeTargetProperties[] {
131-
return _(launchConfig.getSamDebugConfigurations())
132+
async function getSamCodeTargets(launchConfig: LaunchConfiguration): Promise<CodeTargetProperties[]> {
133+
const debugConfigs = await launchConfig.getSamDebugConfigurations()
134+
return _(debugConfigs)
132135
.map(samConfig => samConfig.invokeTarget)
133136
.filter(isCodeTargetProperties)
134137
.value()
@@ -141,18 +144,18 @@ function getSamCodeTargets(launchConfig: LaunchConfiguration): CodeTargetPropert
141144
* @param launchConfig Launch config to check
142145
* @param type target type ('api' or 'template'), or undefined for 'both'
143146
*/
144-
export function getConfigsMappedToTemplates(
147+
export async function getConfigsMappedToTemplates(
145148
launchConfig: LaunchConfiguration,
146149
type: AwsSamTargetType | undefined
147-
): Set<AwsSamDebuggerConfiguration> {
150+
): Promise<Set<AwsSamDebuggerConfiguration>> {
148151
if (type === 'code') {
149152
throw Error()
150153
}
151154
const folder = launchConfig.workspaceFolder
152155
// Launch configs with target=template or target=api.
153-
const templateConfigs = launchConfig
154-
.getSamDebugConfigurations()
155-
.filter(o => isTemplateTargetProperties(o.invokeTarget))
156+
const templateConfigs = (await launchConfig.getSamDebugConfigurations()).filter(o =>
157+
isTemplateTargetProperties(o.invokeTarget)
158+
)
156159
const filtered = templateConfigs.filter(
157160
t =>
158161
(type === undefined || t.invokeTarget.target === type) &&
@@ -175,8 +178,8 @@ export function getConfigsMappedToTemplates(
175178
*
176179
* @param launchConfig Launch config to check
177180
*/
178-
export function getReferencedHandlerPaths(launchConfig: LaunchConfiguration): Set<string> {
179-
const existingSamCodeTargets = getSamCodeTargets(launchConfig)
181+
export async function getReferencedHandlerPaths(launchConfig: LaunchConfiguration): Promise<Set<string>> {
182+
const existingSamCodeTargets = await getSamCodeTargets(launchConfig)
180183

181184
return _(existingSamCodeTargets)
182185
.map(target => {

0 commit comments

Comments
 (0)