1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-05 19:27:05 +00:00

Full support of the http.FileSystem on all view engines as requested at #1575

Also, the HandleDir accepts both string and http.FileSystem (interface{}) (like the view's fs)
This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-09-05 08:34:09 +03:00
parent 7e6d453dad
commit e1f25eb098
50 changed files with 1613 additions and 1226 deletions

View File

@@ -3,8 +3,7 @@ package view
import (
"fmt"
"io"
"os"
"path"
"net/http"
"path/filepath"
"reflect"
"strings"
@@ -18,9 +17,10 @@ const jetEngineName = "jet"
// JetEngine is the jet template parser's view engine.
type JetEngine struct {
directory string
fs http.FileSystem
rootDir string
extension string
// physical system files or app-embedded, see `Binary(..., ...)`. Defaults to file system on initialization.
loader jet.Loader
developmentMode bool
@@ -51,11 +51,12 @@ var jetExtensions = [...]string{
// Jet creates and returns a new jet view engine.
// The given "extension" MUST begin with a dot.
func Jet(directory, extension string) *JetEngine {
// if _, err := os.Stat(directory); os.IsNotExist(err) {
// panic(err)
// }
//
// Usage:
// Jet("./views", ".jet") or
// Jet(iris.Dir("./views"), ".jet") or
// Jet(AssetFile(), ".jet") for embedded data.
func Jet(fs interface{}, extension string) *JetEngine {
extOK := false
for _, ext := range jetExtensions {
if ext == extension {
@@ -69,9 +70,9 @@ func Jet(directory, extension string) *JetEngine {
}
s := &JetEngine{
directory: directory,
rootDir: "/",
extension: extension,
loader: jet.NewOSFileSystemLoader(directory),
loader: &jetLoader{fs: getFS(fs)},
jetDataContextKey: "_jet",
}
@@ -83,6 +84,13 @@ func (s *JetEngine) String() string {
return jetEngineName
}
// RootDir sets the directory to be used as a starting point
// to load templates from the provided file system.
func (s *JetEngine) RootDir(root string) *JetEngine {
s.rootDir = filepath.ToSlash(root)
return s
}
// Ext should return the final file extension which this view engine is responsible to render.
func (s *JetEngine) Ext() string {
return s.extension
@@ -175,121 +183,27 @@ func (s *JetEngine) Reload(developmentMode bool) *JetEngine {
}
// SetLoader can be used when the caller wants to use something like
// multi.Loader or httpfs.Loader of the jet subpackages,
// overrides any previous loader may set by `Binary` or the default.
// Should act before `Load` or `iris.Application#RegisterView`.
// multi.Loader or httpfs.Loader.
func (s *JetEngine) SetLoader(loader jet.Loader) *JetEngine {
s.loader = loader
return s
}
// Binary optionally, use it when template files are distributed
// inside the app executable (.go generated files).
//
// The assetFn and namesFn can come from the go-bindata library.
// Should act before `Load` or `iris.Application#RegisterView`.
func (s *JetEngine) Binary(assetFn func(name string) ([]byte, error), assetNames func() []string) *JetEngine {
// embedded.
vdir := s.directory
if vdir[0] == '.' {
vdir = vdir[1:]
}
// second check for /something, (or ./something if we had dot on 0 it will be removed)
if vdir[0] == '/' || vdir[0] == os.PathSeparator {
vdir = vdir[1:]
}
// check for trailing slashes because new users may be do that by mistake
// although all examples are showing the correct way but you never know
// i.e "./assets/" is not correct, if was inside "./assets".
// remove last "/".
if trailingSlashIdx := len(vdir) - 1; vdir[trailingSlashIdx] == '/' {
vdir = vdir[0:trailingSlashIdx]
}
namesSlice := assetNames()
names := make(map[string]struct{})
for _, name := range namesSlice {
if !strings.HasPrefix(name, vdir) {
continue
}
extOK := false
fileExt := path.Ext(name)
for _, ext := range jetExtensions {
if ext == fileExt {
extOK = true
break
}
}
if !extOK {
continue
}
names[name] = struct{}{}
}
if len(names) == 0 {
panic("JetEngine.Binary: no embedded files found in directory: " + vdir)
}
s.loader = &embeddedLoader{
vdir: vdir,
asset: assetFn,
names: names,
}
return s
type jetLoader struct {
fs http.FileSystem
}
type (
embeddedLoader struct {
vdir string
asset func(name string) ([]byte, error)
names map[string]struct{}
}
embeddedFile struct {
contents []byte // the contents are NOT consumed.
readen int64
}
)
var _ jet.Loader = (*jetLoader)(nil)
var (
_ jet.Loader = (*embeddedLoader)(nil)
_ io.ReadCloser = (*embeddedFile)(nil)
)
func (f *embeddedFile) Close() error { return nil }
func (f *embeddedFile) Read(p []byte) (int, error) {
if f.readen >= int64(len(f.contents)) {
return 0, io.EOF
}
n := copy(p, f.contents[f.readen:])
f.readen += int64(n)
return n, nil
}
// Open opens a file from OS file system.
func (l *embeddedLoader) Open(name string) (io.ReadCloser, error) {
name = path.Join(l.vdir, filepath.ToSlash(name))
contents, err := l.asset(name)
if err != nil {
return nil, err
}
return &embeddedFile{
contents: contents,
}, nil
// Open opens a file from file system.
func (l *jetLoader) Open(name string) (io.ReadCloser, error) {
return l.fs.Open(name)
}
// Exists checks if the template name exists by walking the list of template paths
// returns string with the full path of the template and bool true if the template file was found
func (l *embeddedLoader) Exists(name string) (string, bool) {
name = path.Join(l.vdir, filepath.ToSlash(name))
if _, ok := l.names[name]; ok {
func (l *jetLoader) Exists(name string) (string, bool) {
if _, err := l.fs.Open(name); err == nil {
return name, true
}