Skip to content

Commit d509afa

Browse files
authored
fix: "Scanning CloudFormation templates..." #4020
2 parents e160e1a + ff6dca6 commit d509afa

File tree

6 files changed

+57
-25
lines changed

6 files changed

+57
-25
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "\"Scanning CloudFormation templates...\" message `Cancel` button does not fully stop the scan"
4+
}

src/lambda/commands/createNewSamApp.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ import globals from '../../shared/extensionGlobals'
4848
import { telemetry } from '../../shared/telemetry/telemetry'
4949
import { LambdaArchitecture, Result, Runtime } from '../../shared/telemetry/telemetry'
5050
import { getTelemetryReason, getTelemetryResult } from '../../shared/errors'
51-
import { openUrl } from '../../shared/utilities/vsCodeUtils'
51+
import { openUrl, replaceVscodeVars } from '../../shared/utilities/vsCodeUtils'
5252

5353
export const samInitTemplateFiles: string[] = ['template.yaml', 'template.yml']
5454
export const samInitReadmeFile: string = 'README.TOOLKIT.md'
@@ -395,8 +395,7 @@ export async function addInitialLaunchConfiguration(
395395
const targetDir: string = path.dirname(targetUri.fsPath)
396396
const filtered = configurations.filter(config => {
397397
let templatePath: string = (config.invokeTarget as TemplateTargetProperties).templatePath
398-
// TODO: write utility function that does this for other variables too
399-
templatePath = templatePath.replace('${workspaceFolder}', folder.uri.fsPath)
398+
templatePath = replaceVscodeVars(templatePath, folder.uri.fsPath)
400399

401400
return (
402401
isTemplateTargetProperties(config.invokeTarget) &&

src/shared/fs/templateRegistry.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,20 +87,21 @@ export class AsyncCloudFormationTemplateRegistry {
8787
}
8888

8989
let perf: PerfLog
90-
const cancelSetupPromise = new Timeout(30 * 60 * 1000) // 30 min
90+
const cancelSetup = new Timeout(30 * 60 * 1000) // 30 min
9191
if (!this.setupPromise) {
9292
perf = new PerfLog('cfn: template registry setup')
93-
this.setupPromise = this.asyncSetupFunc(this.instance, cancelSetupPromise)
93+
this.setupPromise = this.asyncSetupFunc(this.instance, cancelSetup)
9494
}
9595
this.setupPromise.then(() => {
9696
if (perf) {
9797
perf.done()
9898
}
9999
this.isSetup = true
100-
cancelSetupPromise.dispose()
100+
cancelSetup.dispose()
101101
})
102102
// Show user a message indicating setup is in progress
103103
if (this.setupProgressMessage === undefined) {
104+
// TODO: use showMessageWithCancel() ?
104105
this.setupProgressMessage = vscode.window.withProgress(
105106
{
106107
location: vscode.ProgressLocation.Notification,
@@ -114,7 +115,7 @@ export class AsyncCloudFormationTemplateRegistry {
114115
token.onCancellationRequested(() => {
115116
// Allows for new message to be created if templateRegistry variable attempted to be used again
116117
this.setupProgressMessage = undefined
117-
cancelSetupPromise.cancel()
118+
cancelSetup.cancel()
118119
})
119120
getLogger().debug('cfn: getInstance() requested, still initializing')
120121
while (!this.isSetup) {

src/shared/fs/watchedFiles.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,21 @@ export function getExcludePattern() {
5757
const getExcludePatternOnce = once(getExcludePattern)
5858

5959
/**
60-
* WatchedFiles lets us index files in the current registry. It is used
60+
* WatchedFiles lets us watch files on the filesystem. It is used
6161
* for CFN templates among other things. WatchedFiles holds a list of pairs of
6262
* the absolute path to the file or "untitled:" URI along with a transform of it that is useful for
6363
* where it is used. For example, for templates, it parses the template and stores it.
6464
*
65-
* Initialize the registry by adding watch patterns and excluded patterns via
66-
* `addWatchPatterns`, `watchUntitledFiles`, and `addExcludedPattern` and then
67-
* calling the `rebuild` function to begin registering files.
65+
* Initialize the registry by adding patterns, followed by a required call to `rebuild`.
66+
67+
* Example:
68+
* ```
69+
* registry.addExcludedPattern(/.*[/\\]\.aws-sam([/\\].*|$)/)
70+
* registry.addExcludedPattern('**\/*.{yaml,yml}')
71+
* registry.addWatchPatterns([/.*devfile\.(yaml|yml)/i])
72+
* registry.watchUntitledFiles()
73+
* await registry.rebuild(cancellationTimeout)
74+
* ```
6875
*/
6976
export abstract class WatchedFiles<T> implements vscode.Disposable {
7077
private isWatching: boolean = false
@@ -284,34 +291,40 @@ export abstract class WatchedFiles<T> implements vscode.Disposable {
284291
/**
285292
* Builds/rebuilds registry using current glob and exclusion patterns. ***Necessary to init registry***.
286293
*
287-
* @param cancellationTimeout Optional timeout that can trigger canceling additional loading on completion (manual or timed)
294+
* @param cancel Optional timeout that can trigger canceling additional loading on completion (manual or timed)
288295
*/
289-
public async rebuild(cancellationTimeout?: Timeout): Promise<void> {
296+
public async rebuild(cancel?: Timeout): Promise<void> {
290297
let skips = 0
298+
let todo = 0
291299
this.isWatching = true
292300
this.reset()
293301

294302
const exclude = getExcludePatternOnce()
295-
getLogger().info(`${this.name}: Building registry with the following criteria: ${this.outputPatterns()}`)
296-
for (let i = 0; i < this.globs.length && !cancellationTimeout?.completed; i++) {
303+
getLogger().info(`${this.name}: building with: ${this.outputPatterns()}`)
304+
for (let i = 0; i < this.globs.length && !cancel?.completed; i++) {
297305
const glob = this.globs[i]
298306
try {
299307
const found = await vscode.workspace.findFiles(glob, exclude)
300-
for (let j = 0; j < found.length && !cancellationTimeout?.completed; j++) {
301-
await this.addItem(found[j], true)
308+
todo = found.length
309+
for (let j = 0; j < found.length && !cancel?.completed; j++, todo--) {
310+
const r = await this.addItem(found[j], true)
311+
if (!r) {
312+
skips++
313+
}
302314
}
303315
} catch (e) {
304-
// file not processable
305-
skips++
306316
const err = e as Error
307-
getLogger().error(`${this.name}: watchedFiles: findFiles("%s", "%s"): %s`, glob, exclude, err.message)
317+
if (err.name !== 'Canceled') {
318+
// vscode may throw nonsense "Canceled" errors when stopping the debugger.
319+
getLogger().error(`%s: findFiles("%s", "%s"): %s`, this.name, glob, exclude, err.message)
320+
}
308321
}
309322
}
310323
getLogger().info(
311-
`${this.name}: Registered %s items%s%s`,
324+
`${this.name}: processed %s items%s%s`,
312325
this.registryData.size,
313-
cancellationTimeout?.completed ? ' (cancelled)' : '',
314-
skips > 0 ? `, skipped ${skips} entries` : ''
326+
cancel?.completed ? ` (cancelled, ${todo} left)` : '',
327+
skips > 0 ? `, skipped ${skips}` : ''
315328
)
316329
}
317330

src/shared/sam/debugger/awsSamDebugConfigurationValidator.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as fs from 'fs'
88
import * as path from 'path'
99
import { samImageLambdaRuntimes, samZipLambdaRuntimes } from '../../../lambda/models/samLambdaRuntime'
1010
import * as CloudFormation from '../../cloudformation/cloudformation'
11-
import { localize } from '../../utilities/vsCodeUtils'
11+
import { localize, replaceVscodeVars } from '../../utilities/vsCodeUtils'
1212
import {
1313
awsSamDebugRequestTypes,
1414
awsSamDebugTargetTypes,
@@ -69,8 +69,13 @@ export class DefaultAwsSamDebugConfigurationValidator implements AwsSamDebugConf
6969
) {
7070
let cfnTemplate: CloudFormation.Template | undefined
7171
if (config.invokeTarget.templatePath) {
72-
const fullpath = tryGetAbsolutePath(this.workspaceFolder, config.invokeTarget.templatePath)
72+
// TODO: why wasn't ${workspaceFolder} resolved before now?
73+
const resolvedPath = replaceVscodeVars(
74+
config.invokeTarget.templatePath,
75+
this.workspaceFolder?.uri.fsPath
76+
)
7377
// Normalize to absolute path for use in the runner.
78+
const fullpath = tryGetAbsolutePath(this.workspaceFolder, resolvedPath)
7479
config.invokeTarget.templatePath = fullpath
7580
// Forcefully add to the registry in case the registry scan somehow missed the file. #2614
7681
// If the user (launch config) gave an explicit path we should always "find" it.

src/shared/utilities/vsCodeUtils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,13 @@ export async function openUrl(url: vscode.Uri): Promise<boolean> {
231231
export function isToolkitActive(): boolean {
232232
return isExtensionActive(VSCODE_EXTENSION_ID.awstoolkit)
233233
}
234+
235+
/**
236+
* Replaces magic vscode variables in a (launch config) user value.
237+
*/
238+
export function replaceVscodeVars(val: string, workspaceFolder?: string): string {
239+
if (!workspaceFolder) {
240+
return val
241+
}
242+
return val.replace('${workspaceFolder}', workspaceFolder)
243+
}

0 commit comments

Comments
 (0)