master
			
			
		
		
							parent
							
								
									f68700b204
								
							
						
					
					
						commit
						98383235f9
					
				@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"html/template"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"io/fs"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						txttmpl "text/template"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Options for getting a template tree
 | 
				
			||||||
 | 
					type Options struct {
 | 
				
			||||||
 | 
						Globs  []string
 | 
				
			||||||
 | 
						Prefix string
 | 
				
			||||||
 | 
						Suffix string
 | 
				
			||||||
 | 
						Root   string
 | 
				
			||||||
 | 
						Funcs  map[string]interface{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o Options) getRoot() string {
 | 
				
			||||||
 | 
						if o.Root == "" {
 | 
				
			||||||
 | 
							return "."
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return o.Root
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o Options) matchesGlob(path string) (bool, error) {
 | 
				
			||||||
 | 
						if len(o.Globs) == 0 {
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, glob := range o.Globs {
 | 
				
			||||||
 | 
							ok, err := filepath.Match(glob, path)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return false, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ok {
 | 
				
			||||||
 | 
								return true, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (o Options) trim(path string) string {
 | 
				
			||||||
 | 
						return strings.TrimSuffix(strings.TrimPrefix(path, o.Prefix), o.Suffix)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Templates returns templates based on a filesystem
 | 
				
			||||||
 | 
					func Templates(files fs.FS, opts Options) (*template.Template, error) {
 | 
				
			||||||
 | 
						var ret *template.Template
 | 
				
			||||||
 | 
						parseTemplates := func(name string, body []byte) error {
 | 
				
			||||||
 | 
							var tmpl *template.Template
 | 
				
			||||||
 | 
							if ret == nil {
 | 
				
			||||||
 | 
								tmpl = template.New(name)
 | 
				
			||||||
 | 
								if opts.Funcs != nil {
 | 
				
			||||||
 | 
									tmpl = tmpl.Funcs(template.FuncMap(opts.Funcs))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								tmpl = ret.New(name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							tmpl, err := tmpl.Parse(string(body))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret = tmpl
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := walk(files, opts, parseTemplates); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TextTemplates returns templates based on a filesystem
 | 
				
			||||||
 | 
					func TextTemplates(files fs.FS, opts Options) (*txttmpl.Template, error) {
 | 
				
			||||||
 | 
						var ret *txttmpl.Template
 | 
				
			||||||
 | 
						parseTemplates := func(name string, body []byte) error {
 | 
				
			||||||
 | 
							var tmpl *txttmpl.Template
 | 
				
			||||||
 | 
							if ret == nil {
 | 
				
			||||||
 | 
								tmpl = txttmpl.New(name)
 | 
				
			||||||
 | 
								if opts.Funcs != nil {
 | 
				
			||||||
 | 
									tmpl = tmpl.Funcs(txttmpl.FuncMap(opts.Funcs))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								tmpl = ret.New(name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							tmpl, err := tmpl.Parse(string(body))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ret = tmpl
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := walk(files, opts, parseTemplates); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func walk(files fs.FS, opts Options, handle func(string, []byte) error) error {
 | 
				
			||||||
 | 
						walker := func(path string, d fs.DirEntry, er error) (err error) {
 | 
				
			||||||
 | 
							if er != nil {
 | 
				
			||||||
 | 
								return er
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							matches, err := opts.matchesGlob(path)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !matches {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							body, err := readfile(files, path)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err := handle(opts.trim(path), body); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := fs.WalkDir(files, opts.getRoot(), walker); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readfile(files fs.FS, path string) ([]byte, error) {
 | 
				
			||||||
 | 
						f, err := files.Open(path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						body, err := io.ReadAll(f)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if err := f.Close(); err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := f.Close(); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return body, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue