1// Package vfstemplate offers text/template helpers that use http.FileSystem. 2package vfstemplate 3 4import ( 5 "fmt" 6 "net/http" 7 "path" 8 "text/template" 9 10 "github.com/shurcooL/httpfs/path/vfspath" 11 "github.com/shurcooL/httpfs/vfsutil" 12) 13 14// ParseFiles creates a new Template if t is nil and parses the template definitions from 15// the named files. The returned template's name will have the (base) name and 16// (parsed) contents of the first file. There must be at least one file. 17// If an error occurs, parsing stops and the returned *Template is nil. 18func ParseFiles(fs http.FileSystem, t *template.Template, filenames ...string) (*template.Template, error) { 19 return parseFiles(fs, t, filenames...) 20} 21 22// ParseGlob parses the template definitions in the files identified by the 23// pattern and associates the resulting templates with t. The pattern is 24// processed by vfspath.Glob and must match at least one file. ParseGlob is 25// equivalent to calling t.ParseFiles with the list of files matched by the 26// pattern. 27func ParseGlob(fs http.FileSystem, t *template.Template, pattern string) (*template.Template, error) { 28 filenames, err := vfspath.Glob(fs, pattern) 29 if err != nil { 30 return nil, err 31 } 32 if len(filenames) == 0 { 33 return nil, fmt.Errorf("vfs/text/vfstemplate: pattern matches no files: %#q", pattern) 34 } 35 return parseFiles(fs, t, filenames...) 36} 37 38// parseFiles is the helper for the method and function. If the argument 39// template is nil, it is created from the first file. 40func parseFiles(fs http.FileSystem, t *template.Template, filenames ...string) (*template.Template, error) { 41 if len(filenames) == 0 { 42 // Not really a problem, but be consistent. 43 return nil, fmt.Errorf("vfs/text/vfstemplate: no files named in call to ParseFiles") 44 } 45 for _, filename := range filenames { 46 b, err := vfsutil.ReadFile(fs, filename) 47 if err != nil { 48 return nil, err 49 } 50 s := string(b) 51 name := path.Base(filename) 52 // First template becomes return value if not already defined, 53 // and we use that one for subsequent New calls to associate 54 // all the templates together. Also, if this file has the same name 55 // as t, this file becomes the contents of t, so 56 // t, err := New(name).Funcs(xxx).ParseFiles(name) 57 // works. Otherwise we create a new template associated with t. 58 var tmpl *template.Template 59 if t == nil { 60 t = template.New(name) 61 } 62 if name == t.Name() { 63 tmpl = t 64 } else { 65 tmpl = t.New(name) 66 } 67 _, err = tmpl.Parse(s) 68 if err != nil { 69 return nil, err 70 } 71 } 72 return t, nil 73} 74