helper.go (hugo-0.80.0) | : | helper.go (hugo-0.81.0) | ||
---|---|---|---|---|
// Copyright 2011 The Go Authors. All rights reserved. | // Copyright 2011 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | // Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | // license that can be found in the LICENSE file. | |||
// Helper functions to make constructing templates easier. | // Helper functions to make constructing templates easier. | |||
package template | package template | |||
import ( | import ( | |||
"fmt" | "fmt" | |||
"io/ioutil" | "io/fs" | |||
"os" | ||||
"path" | ||||
"path/filepath" | "path/filepath" | |||
) | ) | |||
// Functions and methods to parse templates. | // Functions and methods to parse templates. | |||
// Must is a helper that wraps a call to a function returning (*Template, error) | // Must is a helper that wraps a call to a function returning (*Template, error) | |||
// and panics if the error is non-nil. It is intended for use in variable | // and panics if the error is non-nil. It is intended for use in variable | |||
// initializations such as | // initializations such as | |||
// var t = template.Must(template.New("name").Parse("text")) | // var t = template.Must(template.New("name").Parse("text")) | |||
func Must(t *Template, err error) *Template { | func Must(t *Template, err error) *Template { | |||
skipping to change at line 38 | skipping to change at line 40 | |||
// ParseFiles creates a new Template and parses the template definitions from | // ParseFiles creates a new Template and parses the template definitions from | |||
// the named files. The returned template's name will have the base name and | // the named files. The returned template's name will have the base name and | |||
// parsed contents of the first file. There must be at least one file. | // parsed contents of the first file. There must be at least one file. | |||
// If an error occurs, parsing stops and the returned *Template is nil. | // If an error occurs, parsing stops and the returned *Template is nil. | |||
// | // | |||
// When parsing multiple files with the same name in different directories, | // When parsing multiple files with the same name in different directories, | |||
// the last one mentioned will be the one that results. | // the last one mentioned will be the one that results. | |||
// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template | // For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template | |||
// named "foo", while "a/foo" is unavailable. | // named "foo", while "a/foo" is unavailable. | |||
func ParseFiles(filenames ...string) (*Template, error) { | func ParseFiles(filenames ...string) (*Template, error) { | |||
return parseFiles(nil, filenames...) | return parseFiles(nil, readFileOS, filenames...) | |||
} | } | |||
// ParseFiles parses the named files and associates the resulting templates with | // ParseFiles parses the named files and associates the resulting templates with | |||
// t. If an error occurs, parsing stops and the returned template is nil; | // t. If an error occurs, parsing stops and the returned template is nil; | |||
// otherwise it is t. There must be at least one file. | // otherwise it is t. There must be at least one file. | |||
// Since the templates created by ParseFiles are named by the base | // Since the templates created by ParseFiles are named by the base | |||
// names of the argument files, t should usually have the name of one | // names of the argument files, t should usually have the name of one | |||
// of the (base) names of the files. If it does not, depending on t's | // of the (base) names of the files. If it does not, depending on t's | |||
// contents before calling ParseFiles, t.Execute may fail. In that | // contents before calling ParseFiles, t.Execute may fail. In that | |||
// case use t.ExecuteTemplate to execute a valid template. | // case use t.ExecuteTemplate to execute a valid template. | |||
// | // | |||
// When parsing multiple files with the same name in different directories, | // When parsing multiple files with the same name in different directories, | |||
// the last one mentioned will be the one that results. | // the last one mentioned will be the one that results. | |||
func (t *Template) ParseFiles(filenames ...string) (*Template, error) { | func (t *Template) ParseFiles(filenames ...string) (*Template, error) { | |||
t.init() | t.init() | |||
return parseFiles(t, filenames...) | return parseFiles(t, readFileOS, filenames...) | |||
} | } | |||
// parseFiles is the helper for the method and function. If the argument | // parseFiles is the helper for the method and function. If the argument | |||
// template is nil, it is created from the first file. | // template is nil, it is created from the first file. | |||
func parseFiles(t *Template, filenames ...string) (*Template, error) { | func parseFiles(t *Template, readFile func(string) (string, []byte, error), file names ...string) (*Template, error) { | |||
if len(filenames) == 0 { | if len(filenames) == 0 { | |||
// Not really a problem, but be consistent. | // Not really a problem, but be consistent. | |||
return nil, fmt.Errorf("template: no files named in call to Parse Files") | return nil, fmt.Errorf("template: no files named in call to Parse Files") | |||
} | } | |||
for _, filename := range filenames { | for _, filename := range filenames { | |||
b, err := ioutil.ReadFile(filename) | name, b, err := readFile(filename) | |||
if err != nil { | if err != nil { | |||
return nil, err | return nil, err | |||
} | } | |||
s := string(b) | s := string(b) | |||
name := filepath.Base(filename) | ||||
// First template becomes return value if not already defined, | // First template becomes return value if not already defined, | |||
// and we use that one for subsequent New calls to associate | // and we use that one for subsequent New calls to associate | |||
// all the templates together. Also, if this file has the same na me | // all the templates together. Also, if this file has the same na me | |||
// as t, this file becomes the contents of t, so | // as t, this file becomes the contents of t, so | |||
// t, err := New(name).Funcs(xxx).ParseFiles(name) | // t, err := New(name).Funcs(xxx).ParseFiles(name) | |||
// works. Otherwise we create a new template associated with t. | // works. Otherwise we create a new template associated with t. | |||
var tmpl *Template | var tmpl *Template | |||
if t == nil { | if t == nil { | |||
t = New(name) | t = New(name) | |||
} | } | |||
skipping to change at line 129 | skipping to change at line 130 | |||
// parseGlob is the implementation of the function and method ParseGlob. | // parseGlob is the implementation of the function and method ParseGlob. | |||
func parseGlob(t *Template, pattern string) (*Template, error) { | func parseGlob(t *Template, pattern string) (*Template, error) { | |||
filenames, err := filepath.Glob(pattern) | filenames, err := filepath.Glob(pattern) | |||
if err != nil { | if err != nil { | |||
return nil, err | return nil, err | |||
} | } | |||
if len(filenames) == 0 { | if len(filenames) == 0 { | |||
return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) | return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern) | |||
} | } | |||
return parseFiles(t, filenames...) | return parseFiles(t, readFileOS, filenames...) | |||
} | ||||
// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys | ||||
// instead of the host operating system's file system. | ||||
// It accepts a list of glob patterns. | ||||
// (Note that most file names serve as glob patterns matching only themselves.) | ||||
func ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { | ||||
return parseFS(nil, fsys, patterns) | ||||
} | ||||
// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys | ||||
// instead of the host operating system's file system. | ||||
// It accepts a list of glob patterns. | ||||
// (Note that most file names serve as glob patterns matching only themselves.) | ||||
func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { | ||||
t.init() | ||||
return parseFS(t, fsys, patterns) | ||||
} | ||||
func parseFS(t *Template, fsys fs.FS, patterns []string) (*Template, error) { | ||||
var filenames []string | ||||
for _, pattern := range patterns { | ||||
list, err := fs.Glob(fsys, pattern) | ||||
if err != nil { | ||||
return nil, err | ||||
} | ||||
if len(list) == 0 { | ||||
return nil, fmt.Errorf("template: pattern matches no file | ||||
s: %#q", pattern) | ||||
} | ||||
filenames = append(filenames, list...) | ||||
} | ||||
return parseFiles(t, readFileFS(fsys), filenames...) | ||||
} | ||||
func readFileOS(file string) (name string, b []byte, err error) { | ||||
name = filepath.Base(file) | ||||
b, err = os.ReadFile(file) | ||||
return | ||||
} | ||||
func readFileFS(fsys fs.FS) func(string) (string, []byte, error) { | ||||
return func(file string) (name string, b []byte, err error) { | ||||
name = path.Base(file) | ||||
b, err = fs.ReadFile(fsys, file) | ||||
return | ||||
} | ||||
} | } | |||
End of changes. 7 change blocks. | ||||
7 lines changed or deleted | 55 lines changed or added |