@@ -17,16 +17,22 @@ import (
1717 "github.com/spf13/cobra"
1818)
1919
20- var context string = "."
21- var output string = "."
22- var localContext string = "."
20+ var fileContext string = "."
21+ var outputContext string = "."
22+ var sourceContext string = "."
2323
2424var whitespace []string
2525var match []string
2626
2727var verbose bool
2828var recursive bool
29- var preserveStructure bool
29+ var flatten bool
30+
31+ type TemplateContext struct {
32+ invoker string
33+ name string
34+ // ...
35+ }
3036
3137var templateCmd = & cobra.Command {
3238 Use : "template" ,
@@ -55,42 +61,40 @@ func init() {
5561
5662 templateCmd .Flags ().BoolVarP (& recursive , "recursive" , "r" , false , "recusively template files" )
5763 templateCmd .Flags ().BoolVarP (& verbose , "verbose" , "v" , false , "print additional information" )
58- templateCmd .Flags ().BoolVarP (& preserveStructure , "preserve-struct " , "p " , true , "preserves source folder structure in output path " )
64+ templateCmd .Flags ().BoolVarP (& flatten , "flatten " , "f " , false , "flatten output path: don't preserve source folder structure " )
5965
60- templateCmd .Flags ().StringVarP (& output , "output" , "o" , "." , "output path for templated files" )
61- templateCmd .Flags ().StringVarP (& localContext , "source" , "s" , "." , "source path for local files" )
66+ templateCmd .Flags ().StringVarP (& outputContext , "output" , "o" , "." , "output path for templated files" )
67+ templateCmd .Flags ().StringVarP (& sourceContext , "source" , "s" , "." , "source path for local files" )
6268
6369 templateCmd .Flags ().StringSliceVarP (& match , "match" , "m" , []string {".*" }, "regex match for templating" )
6470
6571 templateCmd .Flags ().StringSliceVarP (& whitespace , "whitespace" , "w" , []string {"l" ,"t" }, "remove whitespace from files" )
6672}
6773
6874func run (cmd * cobra.Command , args []string ) {
69- context = args [0 ]
75+ fileContext = args [0 ]
7076
71- fullPath , _ := filepath .Abs (context )
77+ fullPath , _ := filepath .Abs (fileContext )
7278
7379 isDir := fsutils .IsDir (fullPath )
7480 isFile := fsutils .IsFile (fullPath )
7581
7682 if isDir {
77- localContext = context
78-
79- filepath .WalkDir (context , func (path string , d fs.DirEntry , err error ) error {
83+ filepath .WalkDir (fileContext , func (path string , d fs.DirEntry , err error ) error {
8084 if err != nil {
8185 return err
8286 }
8387
8488 if ! d .IsDir () {
8589 handleFile (path )
86- } else if path != context && ! recursive {
90+ } else if path != fileContext && ! recursive {
8791 return filepath .SkipDir
8892 }
8993
9094 return nil
9195 })
9296 } else if isFile {
93- handleFile (context )
97+ handleFile (fileContext )
9498 }
9599}
96100
@@ -145,9 +149,7 @@ func templateFile(relativePath string) error {
145149 return errors .New ("empty file" )
146150 }
147151
148- normalized := normalize (string (data ))
149-
150- tmplStr , err := templateStr ("main" , normalized , nil )
152+ tmplStr , err := templateContent (string (data ), TemplateContext {invoker : relativePath , name : relativePath })
151153
152154 if err != nil {
153155 return err
@@ -156,8 +158,16 @@ func templateFile(relativePath string) error {
156158 return handleFileWrite (tmplStr , relativePath )
157159}
158160
161+ func templateContent (content string , context TemplateContext ) (string , error ) {
162+ normalized := normalize (content )
163+
164+ tmplStr , err := templateStr (normalized , context , nil )
165+
166+ return tmplStr , err
167+ }
168+
159169func handleFileWrite (content , relativePath string ) error {
160- fullPath := fsutils .ResolveOutput (relativePath , output , preserveStructure )
170+ fullPath := fsutils .ResolveOutput (relativePath , outputContext , ! flatten )
161171
162172 if verbose {
163173 fmt .Println ("writing to" , fullPath )
@@ -199,14 +209,28 @@ func removeWhitespace(r rune) bool {
199209 return r == ' ' || r == '\t' || r == '\n' || r == '\r'
200210}
201211
202- func templateGet (key string ) any {
212+ func templateGet (key string , context TemplateContext ) any {
203213 var res string
204214
215+ keyWithoutPrefix := key [4 :]
216+
205217 switch (key [:4 ]) {
206218 case "@://" :
207- res = get .Remote (key [ 4 :] )
219+ res = get .Remote (keyWithoutPrefix )
208220 case "#://" :
209- res = get .Local (key [4 :], localContext )
221+ isRel := strings .HasPrefix (keyWithoutPrefix , "./" ) || strings .HasPrefix (keyWithoutPrefix , "../" )
222+
223+ filePathAbs , _ := filepath .Abs (context .invoker )
224+
225+ if isRel {
226+ res = get .Local (keyWithoutPrefix , filepath .Dir (filePathAbs ))
227+ } else {
228+ res = get .Local (keyWithoutPrefix , sourceContext )
229+ }
230+
231+ keyWithoutPrefix = fsutils .Relative (filepath .Dir (filePathAbs ), keyWithoutPrefix )
232+
233+ fmt .Println (keyWithoutPrefix )
210234 }
211235
212236 if slices .Contains (whitespace , "l" ) {
@@ -217,18 +241,26 @@ func templateGet(key string) any {
217241 res = strings .TrimRightFunc (res , removeWhitespace )
218242 }
219243
244+ fileName := filepath .Base (keyWithoutPrefix )
245+
246+ if matchFile (fileName ) {
247+ res , _ = templateContent (res , TemplateContext {invoker : keyWithoutPrefix , name : keyWithoutPrefix })
248+ }
249+
220250 return res
221251}
222252
223- func templateStr (name , str string , variables map [string ]any ) (string , error ) {
253+ func templateStr (str string , context TemplateContext , variables map [string ]any ) (string , error ) {
224254 tmplStr , err := templating .AddTemplateFunc (str , "get" )
225255
226256 if err != nil {
227257 return str , err
228258 }
229259
230- templt := templating .CreateTemplateWithFunc (name , template.FuncMap {
231- "get" : templateGet ,
260+ templt := templating .CreateTemplateWithFunc (context .name , template.FuncMap {
261+ "get" : func (key string ) any {
262+ return templateGet (key , context )
263+ },
232264 })
233265
234266 tmplStr , err = templating .ParseTemplate (templt , tmplStr , variables )
0 commit comments