@@ -17,7 +17,6 @@ limitations under the License.
1717package parsetemplates
1818
1919import (
20- "fmt"
2120 "os"
2221 "path/filepath"
2322 "reflect"
@@ -33,7 +32,7 @@ func ListTemplatePaths(templatesPath string) ([]string, error) {
3332
3433 tmpl .Funcs (funcs_serdes .FuncMap ())
3534
36- templates := map [* template.Template ]struct {} {}
35+ templates := Set [* template.Template ]{}
3736
3837 // parse all templates
3938 err := filepath .Walk (
@@ -68,79 +67,80 @@ func ListTemplatePaths(templatesPath string) ([]string, error) {
6867 return nil , err
6968 }
7069
71- // remove prefixes
72- templatePaths := make ([]string , 0 , len (templatePathStrings ))
73- for _ , pathString := range templatePathStrings {
74- if ! strings .HasPrefix (pathString , ".$" ) {
75- continue
76- }
77-
78- templatePaths = append (templatePaths , strings .TrimPrefix (pathString , ".$" ))
79- }
70+ return templatePathStrings , nil
71+ }
8072
81- return templatePaths , nil
73+ type templateUsage struct {
74+ node string
75+ context string
8276}
8377
78+ const (
79+ RootNode = "<root-node>"
80+ RootPath = "<root-path>"
81+ )
82+
8483func ListTemplatePathsFromTemplates (
8584 tmpl * template.Template ,
86- templates map [* template.Template ]struct {} ,
85+ templates Set [* template.Template ],
8786) ([]string , error ) {
88- // walk all templates
89- templateResults := map [string ]map [string ]struct {}{}
90- templateUsage := map [string ][][]string {}
87+ // templateResults lists all property paths that are used in a template
88+ templateResults := map [string ]Set [string ]{}
89+ // templateUsage lists all templates that are used in a template
90+ templateUsages := map [string ]Set [templateUsage ]{}
9191 for _ , t := range tmpl .Templates () {
92- root := "$"
93- tmplPath := "$"
94- if _ , ok := templates [t ]; ! ok {
95- // we found a directly parsed template
96- root = ""
97- tmplPath = t .Name ()
92+ var selfNode , selfPath string
93+ if _ , ok := templates [t ]; ok {
94+ // we found a template that is the output of a
95+ // parsed file in the templates folder
96+ selfNode = RootNode
97+ selfPath = RootPath
98+ } else {
99+ // we found a template that is NOT the output
100+ // of a parsed file in the templates folder
101+ selfNode = t .Name ()
102+ selfPath = ""
98103 }
99104
100- result , ok := templateResults [tmplPath ]
101- if ! ok {
102- result = map [string ]struct {}{}
103- templateResults [tmplPath ] = result
104- }
105+ results := getSet (templateResults , selfNode )
106+ usages := getSet (templateUsages , selfNode )
105107
106- walk (t .Root , root , func (path string , node parse.Node , templateName string ) {
107- if node != nil {
108- result [path ] = struct {}{}
109- } else {
110- templateUsage [tmplPath ] = append (templateUsage [tmplPath ], []string {templateName , path })
111- }
112- }, func (varname string , assignName , assign , access * string ) {
113- if assign != nil {
114- varPath := fmt .Sprintf ("%s%s" , tmplPath , varname )
115- assignPath := fmt .Sprintf ("%s%s" , tmplPath , * assignName )
116- templateUsage [assignPath ] = append (templateUsage [assignPath ], []string {varPath , * assign })
117- } else {
118- varPath := fmt .Sprintf ("%s%s" , tmplPath , varname )
119- result , ok := templateResults [varPath ]
120- if ! ok {
121- result = map [string ]struct {}{}
122- templateResults [varPath ] = result
123- }
124-
125- result [* access ] = struct {}{}
126- }
127- })
108+ walk (t .Root , selfNode , selfPath ,
109+ // Found path to a value
110+ func (path string ) {
111+ results .Insert (path )
112+ },
113+ // Found template call
114+ func (templateName string , context string ) {
115+ usages .Insert (templateUsage {templateName , context })
116+ },
117+ // Found local variable usage
118+ func (varname string , path string ) {
119+ getSet (templateResults , joinPath (selfNode , varname )).Insert (path )
120+ },
121+ // Found local variable definition
122+ func (varname string , node , path string ) {
123+ getSet (templateUsages , node ).Insert (templateUsage {joinPath (selfNode , varname ), path })
124+ },
125+ )
128126 }
129127
130- followPath ("$" , templateUsage , func (path , tmplPath string ) {
131- for key := range templateResults [tmplPath ] {
132- templateResults ["$" ][fmt .Sprintf ("%s%s" , path , key )] = struct {}{}
128+ followPath (RootNode , Set [string ]{}, templateUsages , func (node , path string ) {
129+ for key := range templateResults [node ] {
130+ if strings .HasPrefix (key , RootPath ) {
131+ templateResults [RootNode ].Insert (key )
132+ } else {
133+ templateResults [RootNode ].Insert (joinPath (path , key ))
134+ }
133135 }
134136 })
135137
136138 paths := map [string ]struct {}{}
137- for key := range templateResults ["$" ] {
138- if ! strings .HasPrefix (key , "$. Values" ) {
139+ for key := range templateResults [RootNode ] {
140+ if ! strings .HasPrefix (key , joinPath ( RootPath , " Values") ) {
139141 continue
140142 }
141- key = strings .TrimPrefix (key , "$.Values" )
142- key = "$" + key
143-
143+ key = strings .TrimPrefix (key , joinPath (RootPath , "Values" ))
144144 paths [key ] = struct {}{}
145145 }
146146
@@ -156,124 +156,166 @@ func ListTemplatePathsFromTemplates(
156156}
157157
158158func followPath (
159- key string ,
160- templateUsage map [string ][][]string ,
161- run func (path string , tpath string ),
159+ node string ,
160+ visited Set [string ],
161+ templateUsage map [string ]Set [templateUsage ],
162+ run func (node string , path string ),
162163) {
163- for _ , usage := range templateUsage [key ] {
164- followPath (usage [0 ], templateUsage , func (path , tpath string ) {
165- run (fmt .Sprintf ("%s%s" , usage [1 ], path ), tpath )
164+ if visited .Has (node ) {
165+ return
166+ }
167+ visited .Insert (node )
168+
169+ for usage := range templateUsage [node ] {
170+ // Recursively follow the path until we reach the <root-node>
171+ followPath (usage .node , visited , templateUsage , func (node , path string ) {
172+ run (node , joinPath (usage .context , path ))
166173 })
167174 }
168- run ("" , key )
175+ run (node , "" )
176+
177+ visited .Delete (node )
169178}
170179
171180func walk (
172181 node parse.Node ,
182+ parentNode string ,
173183 parentPath string ,
174- foundPathFn func (path string , node parse.Node , templateName string ),
175- foundLocalVar func (varname string , assignPath , assign , access * string ),
184+ // foundPathFn is called when a used path is found
185+ foundPathFn func (path string ),
186+ // foundTemplateFn is called when a template-like call is found
187+ foundTemplateFn func (templateName string , context string ),
188+ // foundVarUsageFn is called when a variable is used
189+ foundVarUsageFn func (varname string , path string ),
190+ // foundVarDefFn is called when a variable is defined
191+ foundVarDefFn func (varname string , node , path string ),
176192) {
177193 if node == nil || reflect .ValueOf (node ).IsNil () {
178194 return
179195 }
180196
181- path := parentPath
182197 switch tn := node .(type ) {
198+ case * parse.DotNode :
199+ foundPathFn (parentPath )
183200 case * parse.FieldNode :
184201 if len (tn .Ident ) == 0 {
185202 } else if tn .Ident [0 ] == "$" {
186- path = strings . Join ( tn .Ident , "." )
203+ foundPathFn ( joinPath ( RootPath , tn .Ident [ 1 :] ... ) )
187204 } else {
188- path = fmt . Sprintf ( "%s.%s" , parentPath , strings . Join ( tn .Ident , "." ))
205+ foundPathFn ( joinPath ( parentPath , tn .Ident ... ))
189206 }
207+ return
190208 case * parse.VariableNode :
191209 if len (tn .Ident ) == 0 {
192210 } else if tn .Ident [0 ] == "$" {
193- path = strings . Join ( tn .Ident , "." )
211+ foundPathFn ( joinPath ( RootPath , tn .Ident [ 1 :] ... ) )
194212 } else if len (tn .Ident [0 ]) >= 1 && tn .Ident [0 ][0 ] == '$' {
195- path := "." + strings .Join (tn .Ident [1 :], "." )
196- foundLocalVar (tn .Ident [0 ], nil , nil , & path )
197- return
213+ foundVarUsageFn (tn .Ident [0 ], joinPath ("" , tn .Ident [1 :]... ))
198214 } else {
199- path = fmt . Sprintf ( "%s.%s" , parentPath , strings . Join ( tn .Ident , "." ))
215+ foundPathFn ( joinPath ( parentPath , tn .Ident ... ))
200216 }
217+ return
201218 }
202219
203- foundPathFn (path , node , "" )
204-
205220 switch tn := node .(type ) {
206221 case * parse.ActionNode :
207- walk (tn .Pipe , path , foundPathFn , foundLocalVar )
222+ walk (tn .Pipe , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
208223 case * parse.ChainNode :
209- walk (tn .Node , path , foundPathFn , foundLocalVar )
224+ walk (tn .Node , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
210225 case * parse.CommandNode :
211226 // handle 'include "test.labels" .' separately
212227 if len (tn .Args ) >= 3 && tn .Args [0 ].String () == "include" && tn .Args [1 ].Type () == parse .NodeString {
213- foundPathFn (getPath (tn .Args [2 ], path ), nil , tn .Args [1 ].(* parse.StringNode ).Text )
228+ foundTemplateFn (
229+ tn .Args [1 ].(* parse.StringNode ).Text ,
230+ getPath (tn .Args [2 ], parentNode , parentPath ),
231+ )
214232 }
215233 for _ , snode := range tn .Args {
216- walk (snode , path , foundPathFn , foundLocalVar )
234+ walk (snode , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
217235 }
218236 case * parse.BranchNode :
219- walk (tn .Pipe , path , foundPathFn , foundLocalVar )
220- walk (tn .List , path , foundPathFn , foundLocalVar )
221- walk (tn .ElseList , path , foundPathFn , foundLocalVar )
237+ walk (tn .Pipe , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
238+ walk (tn .List , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
239+ walk (tn .ElseList , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
222240 case * parse.ListNode :
223241 for _ , snode := range tn .Nodes {
224- walk (snode , path , foundPathFn , foundLocalVar )
242+ walk (snode , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
225243 }
226244 case * parse.PipeNode :
227245 for _ , cmd := range tn .Cmds {
228- walk (cmd , path , foundPathFn , foundLocalVar )
246+ walk (cmd , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
229247 }
230248
231249 for _ , decl := range tn .Decl {
232250 for _ , cmd := range tn .Cmds {
233- walk (cmd , path , func (path string , _ parse.Node , _ string ) {
234- empty := ""
235- foundLocalVar (decl .String (), & empty , & path , nil )
236- }, func (varname string , _ , _ , access * string ) {
237- if access == nil {
238- return
239- }
240- foundLocalVar (decl .String (), & varname , access , nil )
241- })
251+ walk (cmd , parentNode , parentPath ,
252+ func (path string ) {
253+ foundVarDefFn (decl .String (), parentNode , path )
254+ },
255+ func (templateName , context string ) {
256+ foundVarDefFn (decl .String (), templateName , context )
257+ },
258+ func (varname string , path string ) {
259+ foundVarDefFn (decl .String (), joinPath (parentNode , varname ), path )
260+ },
261+ func (varname string , node , path string ) {
262+ // TODO: maybe do something here?
263+ },
264+ )
242265
243266 }
244267 }
245268 case * parse.TemplateNode :
246- path := getPath (tn .Pipe , path )
247- foundPathFn (path , nil , tn .Name )
269+ walk (tn .Pipe , parentNode , parentPath ,
270+ func (path string ) {
271+ foundTemplateFn (tn .Name , path )
272+ },
273+ func (templateName , context string ) {},
274+ func (varname string , path string ) {},
275+ func (varname string , node , path string ) {},
276+ )
248277 case * parse.IfNode :
249- walk (& tn .BranchNode , path , foundPathFn , foundLocalVar )
278+ walk (& tn .BranchNode , parentNode , parentPath , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
250279 case * parse.RangeNode :
251- walk (tn .Pipe , path ,
252- func (path string , node parse.Node , templateName string ) {},
253- func (varname string , assignPath , assign , access * string ) {
254- if assign == nil {
255- return
256- }
257- newAssign := * assign + ".[*]"
258- foundLocalVar (varname , assignPath , & newAssign , access )
280+ walk (tn .Pipe , parentNode , parentPath ,
281+ func (path string ) {
282+ foundPathFn (path + "[*]" )
283+ },
284+ func (templateName , context string ) {
285+ foundTemplateFn (templateName , context + "[*]" )
286+ },
287+ func (varname string , path string ) {
288+ foundVarUsageFn (varname , path + "[*]" )
289+ },
290+ func (varname string , node , path string ) {
291+ foundVarDefFn (varname , node , path + "[*]" )
259292 },
260293 )
261- path := getPath (tn .Pipe , path ) + ". [*]"
262- walk (tn .List , path , foundPathFn , foundLocalVar )
263- walk (tn .ElseList , path , foundPathFn , foundLocalVar )
294+ path := getPath (tn .Pipe , parentNode , parentPath ) + "[*]"
295+ walk (tn .List , parentNode , path , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
296+ walk (tn .ElseList , parentNode , path , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
264297 case * parse.WithNode :
265- path := getPath (tn .Pipe , path )
266- walk (tn .List , path , foundPathFn , foundLocalVar )
267- walk (tn .ElseList , path , foundPathFn , foundLocalVar )
298+ path := getPath (tn .Pipe , parentNode , parentPath )
299+ walk (tn .List , parentNode , path , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
300+ walk (tn .ElseList , parentNode , path , foundPathFn , foundTemplateFn , foundVarUsageFn , foundVarDefFn )
268301 }
269302}
270303
271- func getPath (node parse.Node , parentPath string ) string {
272- longestPath := ""
273- walk (node , parentPath , func (path string , _ parse.Node , _ string ) {
274- if len (path ) > len (longestPath ) {
275- longestPath = path
276- }
277- }, func (varname string , assignPath , assign , access * string ) {})
304+ func getPath (node parse.Node , parentNode string , parentPath string ) string {
305+ longestPath := parentPath
306+ walk (node , parentNode , parentPath ,
307+ func (path string ) {
308+ if len (path ) > len (longestPath ) {
309+ longestPath = path
310+ }
311+ },
312+ func (_ , context string ) {
313+ if len (context ) > len (longestPath ) {
314+ longestPath = context
315+ }
316+ },
317+ func (varname string , path string ) {},
318+ func (varname string , node , path string ) {},
319+ )
278320 return longestPath
279321}
0 commit comments