mirror of
https://github.com/kataras/iris.git
synced 2026-01-07 20:17:05 +00:00
add support for fs.FS, embed.FS (in addition of string and http.FileSystem) for i18n locales and view engine's templates
This commit is contained in:
129
view/fs.go
129
view/fs.go
@@ -2,125 +2,54 @@ package view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/kataras/iris/v12/context"
|
||||
)
|
||||
|
||||
// walk recursively in "fs" descends "root" path, calling "walkFn".
|
||||
func walk(fs http.FileSystem, root string, walkFn filepath.WalkFunc) error {
|
||||
names, err := assetNames(fs, root)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", root, err)
|
||||
// walk recursively in "fileSystem" descends "root" path, calling "walkFn".
|
||||
func walk(fileSystem fs.FS, root string, walkFn filepath.WalkFunc) error {
|
||||
if root != "" && root != "/" && root != "." {
|
||||
sub, err := fs.Sub(fileSystem, root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fileSystem = sub
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
fullpath := path.Join(root, name)
|
||||
f, err := fs.Open(fullpath)
|
||||
if root == "" {
|
||||
root = "."
|
||||
}
|
||||
|
||||
return fs.WalkDir(fileSystem, root, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", fullpath, err)
|
||||
return fmt.Errorf("%s: %w", path, err)
|
||||
}
|
||||
stat, err := f.Stat()
|
||||
err = walkFn(fullpath, stat, err)
|
||||
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
if err != filepath.SkipDir {
|
||||
return fmt.Errorf("%s: %w", fullpath, err)
|
||||
return fmt.Errorf("%s: %w", path, err)
|
||||
}
|
||||
|
||||
continue
|
||||
return nil
|
||||
}
|
||||
|
||||
if stat.IsDir() {
|
||||
if err := walk(fs, fullpath, walkFn); err != nil {
|
||||
return fmt.Errorf("%s: %w", fullpath, err)
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return walkFn(path, info, err)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// assetNames returns the first-level directories and file, sorted, names.
|
||||
func assetNames(fs http.FileSystem, name string) ([]string, error) {
|
||||
f, err := fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if f == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
infos, err := f.Readdir(-1)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
names := make([]string, 0, len(infos))
|
||||
for _, info := range infos {
|
||||
// note: go-bindata fs returns full names whether
|
||||
// the http.Dir returns the base part, so
|
||||
// we only work with their base names.
|
||||
name := filepath.ToSlash(info.Name())
|
||||
name = path.Base(name)
|
||||
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
return names, nil
|
||||
func asset(fileSystem fs.FS, name string) ([]byte, error) {
|
||||
return fs.ReadFile(fileSystem, name)
|
||||
}
|
||||
|
||||
func asset(fs http.FileSystem, name string) ([]byte, error) {
|
||||
f, err := fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contents, err := io.ReadAll(f)
|
||||
f.Close()
|
||||
return contents, err
|
||||
}
|
||||
|
||||
func getFS(fsOrDir interface{}) (fs http.FileSystem) {
|
||||
if fsOrDir == nil {
|
||||
return noOpFS{}
|
||||
}
|
||||
|
||||
if v, ok := fsOrDir.(string); ok {
|
||||
if v == "" {
|
||||
fs = noOpFS{}
|
||||
} else {
|
||||
fs = httpDirWrapper{http.Dir(v)}
|
||||
}
|
||||
} else {
|
||||
fs = context.ResolveFS(fsOrDir)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type noOpFS struct{}
|
||||
|
||||
func (fs noOpFS) Open(name string) (http.File, error) { return nil, nil }
|
||||
|
||||
func isNoOpFS(fs http.FileSystem) bool {
|
||||
_, ok := fs.(noOpFS)
|
||||
return ok
|
||||
}
|
||||
|
||||
// fixes: "invalid character in file path"
|
||||
// on amber engine (it uses the virtual fs directly
|
||||
// and it uses filepath instead of the path package...).
|
||||
type httpDirWrapper struct {
|
||||
http.Dir
|
||||
}
|
||||
|
||||
func (fs httpDirWrapper) Open(name string) (http.File, error) {
|
||||
return fs.Dir.Open(filepath.ToSlash(name))
|
||||
func getFS(fsOrDir interface{}) fs.FS {
|
||||
return context.ResolveFS(fsOrDir)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user