4
4
*/
5
5
6
6
import * as vscode from 'vscode'
7
- import * as path_ from 'path'
8
7
import { getLogger } from '../logger/logger'
9
8
import { CloudFormation } from './cloudformation'
10
9
import * as pathutils from '../utilities/pathUtils'
10
+ import * as path from 'path'
11
11
import { isInDirectory } from '../filesystemUtilities'
12
12
import { dotNetRuntimes } from '../../lambda/models/samLambdaRuntime'
13
13
import { getLambdaDetails } from '../../lambda/utils'
14
+ import { ext } from '../extensionGlobals'
14
15
15
16
export interface TemplateDatum {
16
17
path : string
17
18
template : CloudFormation . Template
18
19
}
19
20
20
- export class CloudFormationTemplateRegistry {
21
- private static INSTANCE : CloudFormationTemplateRegistry | undefined
22
- private readonly templateRegistryData : Map < string , CloudFormation . Template >
21
+ export class CloudFormationTemplateRegistry implements vscode . Disposable {
22
+ private readonly disposables : vscode . Disposable [ ] = [ ]
23
+ private _isDisposed : boolean = false
24
+ private readonly globs : vscode . GlobPattern [ ] = [ ]
25
+ private readonly excludedFilePatterns : RegExp [ ] = [ ]
26
+ private readonly templateRegistryData : Map < string , CloudFormation . Template > = new Map <
27
+ string ,
28
+ CloudFormation . Template
29
+ > ( )
23
30
24
31
public constructor ( ) {
25
- this . templateRegistryData = new Map < string , CloudFormation . Template > ( )
32
+ this . disposables . push (
33
+ vscode . workspace . onDidChangeWorkspaceFolders ( async ( ) => {
34
+ await this . rebuildRegistry ( )
35
+ } )
36
+ )
26
37
}
27
38
28
- private assertAbsolute ( path : string ) {
29
- if ( ! path_ . isAbsolute ( path ) ) {
30
- throw Error ( `CloudFormationTemplateRegistry: path is relative: ${ path } ` )
39
+ /**
40
+ * Adds a glob pattern to use for lookups and resets the registry to use it.
41
+ * Added templates cannot be removed without restarting the extension.
42
+ * Throws an error if this manager has already been disposed.
43
+ * @param glob vscode.GlobPattern to be used for lookups
44
+ */
45
+ public async addTemplateGlob ( glob : vscode . GlobPattern ) : Promise < void > {
46
+ if ( this . _isDisposed ) {
47
+ throw new Error ( 'Manager has already been disposed!' )
48
+ }
49
+ this . globs . push ( glob )
50
+
51
+ const watcher = vscode . workspace . createFileSystemWatcher ( glob )
52
+ this . addWatcher ( watcher )
53
+
54
+ await this . rebuildRegistry ( )
55
+ }
56
+
57
+ /**
58
+ * Adds a regex pattern to ignore paths containing the pattern
59
+ */
60
+ public async addExcludedPattern ( pattern : RegExp ) : Promise < void > {
61
+ if ( this . _isDisposed ) {
62
+ throw new Error ( 'Manager has already been disposed!' )
31
63
}
64
+ this . excludedFilePatterns . push ( pattern )
65
+
66
+ await this . rebuildRegistry ( )
32
67
}
33
68
34
69
/**
35
70
* Adds template to registry. Wipes any existing template in its place with newly-parsed copy of the data.
36
71
* @param templateUri vscode.Uri containing the template to load in
37
72
*/
38
73
public async addTemplateToRegistry ( templateUri : vscode . Uri , quiet ?: boolean ) : Promise < void > {
74
+ const excluded = this . excludedFilePatterns . find ( pattern => templateUri . fsPath . match ( pattern ) )
75
+ if ( excluded ) {
76
+ getLogger ( ) . verbose (
77
+ `Manager did not add template ${ templateUri . fsPath } matching excluded pattern ${ excluded } `
78
+ )
79
+ return
80
+ }
39
81
const pathAsString = pathutils . normalize ( templateUri . fsPath )
40
82
this . assertAbsolute ( pathAsString )
41
83
try {
@@ -91,6 +133,35 @@ export class CloudFormationTemplateRegistry {
91
133
this . templateRegistryData . delete ( pathAsString )
92
134
}
93
135
136
+ /**
137
+ * Disposes CloudFormationTemplateRegistryManager and marks as disposed.
138
+ */
139
+ public dispose ( ) : void {
140
+ if ( ! this . _isDisposed ) {
141
+ while ( this . disposables . length > 0 ) {
142
+ const disposable = this . disposables . pop ( )
143
+ if ( disposable ) {
144
+ disposable . dispose ( )
145
+ }
146
+ }
147
+ this . _isDisposed = true
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Rebuilds registry using current glob and exclusion patterns.
153
+ * All functionality is currently internal to class, but can be made public if we want a manual "refresh" button
154
+ */
155
+ private async rebuildRegistry ( ) : Promise < void > {
156
+ this . reset ( )
157
+ for ( const glob of this . globs ) {
158
+ const templateUris = await vscode . workspace . findFiles ( glob )
159
+ for ( const template of templateUris ) {
160
+ await this . addTemplateToRegistry ( template , true )
161
+ }
162
+ }
163
+ }
164
+
94
165
/**
95
166
* Removes all templates from the registry.
96
167
*/
@@ -99,15 +170,31 @@ export class CloudFormationTemplateRegistry {
99
170
}
100
171
101
172
/**
102
- * Returns the CloudFormationTemplateRegistry singleton.
103
- * If the singleton doesn't exist, creates it.
173
+ * Sets watcher functionality and adds to this.disposables
174
+ * @param watcher vscode.FileSystemWatcher
104
175
*/
105
- public static getRegistry ( ) : CloudFormationTemplateRegistry {
106
- if ( ! CloudFormationTemplateRegistry . INSTANCE ) {
107
- CloudFormationTemplateRegistry . INSTANCE = new CloudFormationTemplateRegistry ( )
108
- }
176
+ private addWatcher ( watcher : vscode . FileSystemWatcher ) : void {
177
+ this . disposables . push (
178
+ watcher ,
179
+ watcher . onDidChange ( async uri => {
180
+ getLogger ( ) . verbose ( `Manager detected a change to template file: ${ uri . fsPath } ` )
181
+ await this . addTemplateToRegistry ( uri )
182
+ } ) ,
183
+ watcher . onDidCreate ( async uri => {
184
+ getLogger ( ) . verbose ( `Manager detected a new template file: ${ uri . fsPath } ` )
185
+ await this . addTemplateToRegistry ( uri )
186
+ } ) ,
187
+ watcher . onDidDelete ( async uri => {
188
+ getLogger ( ) . verbose ( `Manager detected a deleted template file: ${ uri . fsPath } ` )
189
+ this . removeTemplateFromRegistry ( uri )
190
+ } )
191
+ )
192
+ }
109
193
110
- return CloudFormationTemplateRegistry . INSTANCE
194
+ private assertAbsolute ( p : string ) {
195
+ if ( ! path . isAbsolute ( p ) ) {
196
+ throw Error ( `CloudFormationTemplateRegistry: path is relative: ${ p } ` )
197
+ }
111
198
}
112
199
}
113
200
@@ -121,7 +208,7 @@ export class CloudFormationTemplateRegistry {
121
208
export function getResourcesForHandler (
122
209
filepath : string ,
123
210
handler : string ,
124
- unfilteredTemplates : TemplateDatum [ ] = CloudFormationTemplateRegistry . getRegistry ( ) . registeredTemplates
211
+ unfilteredTemplates : TemplateDatum [ ] = ext . templateRegistry . registeredTemplates
125
212
) : { templateDatum : TemplateDatum ; name : string ; resourceData : CloudFormation . Resource } [ ] {
126
213
// TODO: Array.flat and Array.flatMap not introduced until >= Node11.x -- migrate when VS Code updates Node ver
127
214
const o = unfilteredTemplates . map ( templateDatum => {
@@ -150,9 +237,9 @@ export function getResourcesForHandlerFromTemplateDatum(
150
237
templateDatum : TemplateDatum
151
238
) : { name : string ; resourceData : CloudFormation . Resource } [ ] {
152
239
const matchingResources : { name : string ; resourceData : CloudFormation . Resource } [ ] = [ ]
153
- const templateDirname = path_ . dirname ( templateDatum . path )
240
+ const templateDirname = path . dirname ( templateDatum . path )
154
241
// template isn't a parent or sibling of file
155
- if ( ! isInDirectory ( templateDirname , path_ . dirname ( filepath ) ) ) {
242
+ if ( ! isInDirectory ( templateDirname , path . dirname ( filepath ) ) ) {
156
243
return [ ]
157
244
}
158
245
@@ -191,7 +278,7 @@ export function getResourcesForHandlerFromTemplateDatum(
191
278
if (
192
279
handler === registeredHandler &&
193
280
isInDirectory (
194
- pathutils . normalize ( path_ . join ( templateDirname , registeredCodeUri ) ) ,
281
+ pathutils . normalize ( path . join ( templateDirname , registeredCodeUri ) ) ,
195
282
pathutils . normalize ( filepath )
196
283
)
197
284
) {
@@ -210,7 +297,7 @@ export function getResourcesForHandlerFromTemplateDatum(
210
297
if (
211
298
pathutils . normalize ( filepath ) ===
212
299
pathutils . normalize (
213
- path_ . join ( templateDirname , registeredCodeUri , parsedLambda . fileName )
300
+ path . join ( templateDirname , registeredCodeUri , parsedLambda . fileName )
214
301
) &&
215
302
functionName === parsedLambda . functionName
216
303
) {
0 commit comments