mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01: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:
parent
4cd0621018
commit
512ed6ffc0
|
@ -29,10 +29,10 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
- Support of embedded [locale files](https://github.com/kataras/iris/blob/master/_examples/i18n/template-embedded/main.go) using standard `embed.FS` with the new `LoadFS` function.
|
- Support of embedded [locale files](https://github.com/kataras/iris/blob/master/_examples/i18n/template-embedded/main.go) using standard `embed.FS` with the new `LoadFS` function.
|
||||||
- Support of direct embedded view templates with `embed.FS` or `fs.FS` (in addition to `string` and `http.FileSystem` types).
|
- Support of direct embedded view engines (`HTML, Blocks, Django, Handlebars, Pug, Amber, Jet` and `Ace`) with `embed.FS` or `fs.FS` (in addition to `string` and `http.FileSystem` types).
|
||||||
|
- Add support for `embed.FS` and `fs.FS` on `app.HandleDir`.
|
||||||
|
|
||||||
- Add `iris.Patches()` package-level function to customize Iris Request Context REST (and more to come) behavior.
|
- Add `iris.Patches()` package-level function to customize Iris Request Context REST (and more to come) behavior.
|
||||||
- Add support for `embed.FS` and `fs.FS` on `app.HandleDir`.
|
|
||||||
- Minor fixes.
|
- Minor fixes.
|
||||||
|
|
||||||
- Enable setting a custom "go-redis" client through `SetClient` go redis driver method or `Client` struct field on sessions/database/redis driver as requested at [chat](https://chat.iris-go.com).
|
- Enable setting a custom "go-redis" client through `SetClient` go redis driver method or `Client` struct field on sessions/database/redis driver as requested at [chat](https://chat.iris-go.com).
|
||||||
|
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"github.com/kataras/iris/v12"
|
"github.com/kataras/iris/v12"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed locales/*
|
//go:embed embedded/locales/*
|
||||||
var filesystem embed.FS
|
var embeddedFS embed.FS
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := newApp()
|
app := newApp()
|
||||||
|
@ -31,7 +31,7 @@ func newApp() *iris.Application {
|
||||||
// Instead of:
|
// Instead of:
|
||||||
// err := app.I18n.Load("./locales/*/*.ini", "en-US", "el-GR")
|
// err := app.I18n.Load("./locales/*/*.ini", "en-US", "el-GR")
|
||||||
// Apply the below in order to build with embedded locales inside your executable binary.
|
// Apply the below in order to build with embedded locales inside your executable binary.
|
||||||
err := app.I18n.LoadFS(filesystem, ".", "en-US", "el-GR")
|
err := app.I18n.LoadFS(embeddedFS, "./embedded/locales/*/*.ini", "en-US", "el-GR")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,6 @@
|
||||||
{{ template "content" .}}
|
{{ template "content" .}}
|
||||||
|
|
||||||
|
|
||||||
<h4>Copyright © 2020 Admin</h4>
|
<h4>Copyright © 2022 Admin</h4>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -7,13 +7,14 @@ import (
|
||||||
"github.com/kataras/iris/v12/x/errors"
|
"github.com/kataras/iris/v12/x/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed templates/*
|
//go:embed embedded/*
|
||||||
var embeddedTemplatesFS embed.FS
|
var embeddedFS embed.FS
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := iris.New()
|
app := iris.New()
|
||||||
|
|
||||||
tmpl := iris.HTML(embeddedTemplatesFS, ".html")
|
tmpl := iris.HTML(embeddedFS, ".html").RootDir("embedded/templates")
|
||||||
|
|
||||||
tmpl.Layout("layouts/layout.html")
|
tmpl.Layout("layouts/layout.html")
|
||||||
tmpl.AddFunc("greet", func(s string) string {
|
tmpl.AddFunc("greet", func(s string) string {
|
||||||
return "Greetings " + s + "!"
|
return "Greetings " + s + "!"
|
||||||
|
|
14
aliases.go
14
aliases.go
|
@ -1,6 +1,7 @@
|
||||||
package iris
|
package iris
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
@ -805,10 +806,15 @@ func (cp *ContextPatches) SetCookieKVExpiration(patch time.Duration) {
|
||||||
context.SetCookieKVExpiration = patch
|
context.SetCookieKVExpiration = patch
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveFS modifies the default way to resolve a filesystem by any type of value.
|
// ResolveHTTPFS modifies the default way to resolve a filesystem by any type of value.
|
||||||
// It affects the view engine filesystem resolver
|
// It affects the Application's API Builder's `HandleDir` method.
|
||||||
// and the Application's API Builder's `HandleDir` method.
|
func (cp *ContextPatches) ResolveHTTPFS(patchFunc func(fsOrDir interface{}) http.FileSystem) {
|
||||||
func (cp *ContextPatches) ResolveFS(patchFunc func(fsOrDir interface{}) http.FileSystem) {
|
context.ResolveHTTPFS = patchFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveHTTPFS modifies the default way to resolve a filesystem by any type of value.
|
||||||
|
// It affects the view engine's filesystem resolver.
|
||||||
|
func (cp *ContextPatches) ResolveFS(patchFunc func(fsOrDir interface{}) fs.FS) {
|
||||||
context.ResolveFS = patchFunc
|
context.ResolveFS = patchFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,17 +5,102 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResolveFS accepts a single input argument of any type
|
// ResolveFS accepts a single input argument of any type
|
||||||
// and tries to cast it to http.FileSystem.
|
// and tries to cast it to fs.FS.
|
||||||
//
|
//
|
||||||
// It affects the view engine filesystem resolver
|
// It affects the view engine's filesystem resolver.
|
||||||
// and the Application's API Builder's `HandleDir` method.
|
|
||||||
//
|
//
|
||||||
// This package-level variable can be modified on initialization.
|
// This package-level variable can be modified on initialization.
|
||||||
var ResolveFS = func(fsOrDir interface{}) http.FileSystem {
|
var ResolveFS = func(fsOrDir interface{}) fs.FS {
|
||||||
|
if fsOrDir == nil {
|
||||||
|
return noOpFS{}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := fsOrDir.(type) {
|
||||||
|
case string:
|
||||||
|
if v == "" {
|
||||||
|
return noOpFS{}
|
||||||
|
}
|
||||||
|
return os.DirFS(v)
|
||||||
|
case fs.FS:
|
||||||
|
return v
|
||||||
|
case http.FileSystem: // handles go-bindata.
|
||||||
|
return &httpFS{v}
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf(`unexpected "fsOrDir" argument type of %T (string or fs.FS or embed.FS or http.FileSystem)`, v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noOpFS struct{}
|
||||||
|
|
||||||
|
func (fileSystem noOpFS) Open(name string) (fs.File, error) { return nil, nil }
|
||||||
|
|
||||||
|
// IsNoOpFS reports whether the given "fileSystem" is a no operation fs.
|
||||||
|
func IsNoOpFS(fileSystem fs.FS) bool {
|
||||||
|
_, ok := fileSystem.(noOpFS)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpFS struct {
|
||||||
|
fs http.FileSystem
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *httpFS) Open(name string) (fs.File, error) {
|
||||||
|
if name == "." {
|
||||||
|
name = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.fs.Open(filepath.ToSlash(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *httpFS) ReadDir(name string) ([]fs.DirEntry, error) {
|
||||||
|
name = filepath.ToSlash(name)
|
||||||
|
if name == "." {
|
||||||
|
name = "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := f.fs.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
infos, err := file.Readdir(-1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entries := make([]fs.DirEntry, 0, len(infos))
|
||||||
|
for _, info := range infos {
|
||||||
|
if info.IsDir() { // http file's does not return the whole tree, so read it.
|
||||||
|
sub, err := f.ReadDir(info.Name())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
entries = append(entries, sub...)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
entry := fs.FileInfoToDirEntry(info)
|
||||||
|
entries = append(entries, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveHTTPFS accepts a single input argument of any type
|
||||||
|
// and tries to cast it to http.FileSystem.
|
||||||
|
//
|
||||||
|
// It affects the Application's API Builder's `HandleDir` method.
|
||||||
|
//
|
||||||
|
// This package-level variable can be modified on initialization.
|
||||||
|
var ResolveHTTPFS = func(fsOrDir interface{}) http.FileSystem {
|
||||||
var fileSystem http.FileSystem
|
var fileSystem http.FileSystem
|
||||||
switch v := fsOrDir.(type) {
|
switch v := fsOrDir.(type) {
|
||||||
case string:
|
case string:
|
||||||
|
|
|
@ -635,7 +635,7 @@ func (api *APIBuilder) HandleDir(requestPath string, fsOrDir interface{}, opts .
|
||||||
options = opts[0]
|
options = opts[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
fs := context.ResolveFS(fsOrDir)
|
fs := context.ResolveHTTPFS(fsOrDir)
|
||||||
h := FileServer(fs, options)
|
h := FileServer(fs, options)
|
||||||
description := "file server"
|
description := "file server"
|
||||||
if d, ok := fs.(http.Dir); ok {
|
if d, ok := fs.(http.Dir); ok {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -22,7 +22,7 @@ require (
|
||||||
github.com/iris-contrib/jade v1.1.4
|
github.com/iris-contrib/jade v1.1.4
|
||||||
github.com/iris-contrib/schema v0.0.6
|
github.com/iris-contrib/schema v0.0.6
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/kataras/blocks v0.0.6
|
github.com/kataras/blocks v0.0.7
|
||||||
github.com/kataras/golog v0.1.7
|
github.com/kataras/golog v0.1.7
|
||||||
github.com/kataras/jwt v0.1.8
|
github.com/kataras/jwt v0.1.8
|
||||||
github.com/kataras/neffos v0.0.20
|
github.com/kataras/neffos v0.0.20
|
||||||
|
|
4
go.sum
generated
4
go.sum
generated
|
@ -105,8 +105,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/kataras/blocks v0.0.6 h1:UQI+2AMxhUoe5WcyAT0AdPHTSMcrPy+ALAgvYj2vPwo=
|
github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4=
|
||||||
github.com/kataras/blocks v0.0.6/go.mod h1:UK+Iwk0Oxpc0GdoJja7sEildotAUKK1LYeYcVF0COWc=
|
github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I=
|
||||||
github.com/kataras/golog v0.1.7 h1:0TY5tHn5L5DlRIikepcaRR/6oInIr9AiWsxzt0vvlBE=
|
github.com/kataras/golog v0.1.7 h1:0TY5tHn5L5DlRIikepcaRR/6oInIr9AiWsxzt0vvlBE=
|
||||||
github.com/kataras/golog v0.1.7/go.mod h1:jOSQ+C5fUqsNSwurB/oAHq1IFSb0KI3l6GMa7xB6dZA=
|
github.com/kataras/golog v0.1.7/go.mod h1:jOSQ+C5fUqsNSwurB/oAHq1IFSb0KI3l6GMa7xB6dZA=
|
||||||
github.com/kataras/jwt v0.1.8 h1:u71baOsYD22HWeSOg32tCHbczPjdCk7V4MMeJqTtmGk=
|
github.com/kataras/jwt v0.1.8 h1:u71baOsYD22HWeSOg32tCHbczPjdCk7V4MMeJqTtmGk=
|
||||||
|
|
|
@ -4,6 +4,7 @@ package i18n
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -142,12 +143,12 @@ func (i *I18n) LoadAssets(assetNames func() []string, asset func(string) ([]byte
|
||||||
|
|
||||||
// LoadFS is a method shortcut to load files using `embed.FS` or `fs.FS` or
|
// LoadFS is a method shortcut to load files using `embed.FS` or `fs.FS` or
|
||||||
// `http.FileSystem` or `string` (local directory).
|
// `http.FileSystem` or `string` (local directory).
|
||||||
// With this method, all the embedded files into "sub" MUST be locale files.
|
// The "pattern" is a classic glob pattern.
|
||||||
//
|
//
|
||||||
// See `New` and `FS` package-level functions for more.
|
// See `New` and `FS` package-level functions for more.
|
||||||
// Example: https://github.com/kataras/iris/blob/master/_examples/i18n/template-embedded/main.go.
|
// Example: https://github.com/kataras/iris/blob/master/_examples/i18n/template-embedded/main.go.
|
||||||
func (i *I18n) LoadFS(fsOrDir interface{}, sub string, languages ...string) error {
|
func (i *I18n) LoadFS(fileSystem fs.FS, pattern string, languages ...string) error {
|
||||||
loader, err := FS(fsOrDir, sub, i.Loader)
|
loader, err := FS(fileSystem, pattern, i.Loader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/context"
|
|
||||||
"github.com/kataras/iris/v12/i18n/internal"
|
"github.com/kataras/iris/v12/i18n/internal"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
@ -50,17 +50,13 @@ func Assets(assetNames func() []string, asset func(string) ([]byte, error), opti
|
||||||
|
|
||||||
// LoadFS loads the files using embed.FS or fs.FS or
|
// LoadFS loads the files using embed.FS or fs.FS or
|
||||||
// http.FileSystem or string (local directory).
|
// http.FileSystem or string (local directory).
|
||||||
// With this method, all the embedded files into "sub" MUST be locale files.
|
// The "pattern" is a classic glob pattern.
|
||||||
//
|
//
|
||||||
// See `Glob`, `Assets`, `New` and `LoaderConfig` too.
|
// See `Glob`, `Assets`, `New` and `LoaderConfig` too.
|
||||||
func FS(fsOrDir interface{}, sub string, options LoaderConfig) (Loader, error) {
|
func FS(fileSystem fs.FS, pattern string, options LoaderConfig) (Loader, error) {
|
||||||
if sub == "" {
|
pattern = strings.TrimPrefix(pattern, "./")
|
||||||
sub = "."
|
|
||||||
}
|
|
||||||
|
|
||||||
fileSystem := context.ResolveFS(fsOrDir)
|
assetNames, err := fs.Glob(fileSystem, pattern)
|
||||||
|
|
||||||
assetNames, err := context.FindNames(fileSystem, sub)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,7 +154,7 @@ func hi(ctx iris.Context) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
A real example can be found here: https://github.com/kataras/iris/tree/master/_examples/view/embedding-templates-into-app.
|
Examples can be found here: https://github.com/kataras/iris/tree/master/_examples/view/embedding-templates-into-app and https://github.com/kataras/iris/tree/master/_examples/view/embedding-templates-into-app-bindata.
|
||||||
|
|
||||||
## Reload
|
## Reload
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ func (s *AceEngine) SetIndent(indent string) *AceEngine {
|
||||||
// Usage:
|
// Usage:
|
||||||
// Ace("./views", ".ace") or
|
// Ace("./views", ".ace") or
|
||||||
// Ace(iris.Dir("./views"), ".ace") or
|
// Ace(iris.Dir("./views"), ".ace") or
|
||||||
// Ace(AssetFile(), ".ace") for embedded data.
|
// Ace(embed.FS, ".ace") or Ace(AssetFile(), ".ace") for embedded data.
|
||||||
func Ace(fs interface{}, extension string) *AceEngine {
|
func Ace(fs interface{}, extension string) *AceEngine {
|
||||||
s := &AceEngine{HTMLEngine: HTML(fs, extension), indent: ""}
|
s := &AceEngine{HTMLEngine: HTML(fs, extension), indent: ""}
|
||||||
s.name = "Ace"
|
s.name = "Ace"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -17,7 +18,7 @@ import (
|
||||||
|
|
||||||
// AmberEngine contains the amber view engine structure.
|
// AmberEngine contains the amber view engine structure.
|
||||||
type AmberEngine struct {
|
type AmberEngine struct {
|
||||||
fs http.FileSystem
|
fs fs.FS
|
||||||
// files configuration
|
// files configuration
|
||||||
rootDir string
|
rootDir string
|
||||||
extension string
|
extension string
|
||||||
|
@ -43,15 +44,15 @@ var amberOnce = new(uint32)
|
||||||
// Usage:
|
// Usage:
|
||||||
// Amber("./views", ".amber") or
|
// Amber("./views", ".amber") or
|
||||||
// Amber(iris.Dir("./views"), ".amber") or
|
// Amber(iris.Dir("./views"), ".amber") or
|
||||||
// Amber(AssetFile(), ".amber") for embedded data.
|
// Amber(embed.FS, ".amber") or Amber(AssetFile(), ".amber") for embedded data.
|
||||||
func Amber(fs interface{}, extension string) *AmberEngine {
|
func Amber(dirOrFS interface{}, extension string) *AmberEngine {
|
||||||
if atomic.LoadUint32(amberOnce) > 0 {
|
if atomic.LoadUint32(amberOnce) > 0 {
|
||||||
panic("Amber: cannot be registered twice as its internal implementation share the same template functions across instances.")
|
panic("Amber: cannot be registered twice as its internal implementation share the same template functions across instances.")
|
||||||
} else {
|
} else {
|
||||||
atomic.StoreUint32(amberOnce, 1)
|
atomic.StoreUint32(amberOnce, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileSystem := getFS(fs)
|
fileSystem := getFS(dirOrFS)
|
||||||
s := &AmberEngine{
|
s := &AmberEngine{
|
||||||
fs: fileSystem,
|
fs: fileSystem,
|
||||||
rootDir: "/",
|
rootDir: "/",
|
||||||
|
@ -60,7 +61,7 @@ func Amber(fs interface{}, extension string) *AmberEngine {
|
||||||
Options: amber.Options{
|
Options: amber.Options{
|
||||||
PrettyPrint: false,
|
PrettyPrint: false,
|
||||||
LineNumbers: false,
|
LineNumbers: false,
|
||||||
VirtualFilesystem: fileSystem,
|
VirtualFilesystem: http.FS(fileSystem),
|
||||||
},
|
},
|
||||||
bufPool: &sync.Pool{New: func() interface{} {
|
bufPool: &sync.Pool{New: func() interface{} {
|
||||||
return new(bytes.Buffer)
|
return new(bytes.Buffer)
|
||||||
|
@ -84,6 +85,15 @@ func Amber(fs interface{}, extension string) *AmberEngine {
|
||||||
// RootDir sets the directory to be used as a starting point
|
// RootDir sets the directory to be used as a starting point
|
||||||
// to load templates from the provided file system.
|
// to load templates from the provided file system.
|
||||||
func (s *AmberEngine) RootDir(root string) *AmberEngine {
|
func (s *AmberEngine) RootDir(root string) *AmberEngine {
|
||||||
|
if s.fs != nil && root != "" && root != "/" && root != "." && root != s.rootDir {
|
||||||
|
sub, err := fs.Sub(s.fs, s.rootDir)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.fs = sub // here so the "middleware" can work.
|
||||||
|
}
|
||||||
|
|
||||||
s.rootDir = filepath.ToSlash(root)
|
s.rootDir = filepath.ToSlash(root)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -142,7 +152,7 @@ func (s *AmberEngine) AddFunc(funcName string, funcBody interface{}) {
|
||||||
//
|
//
|
||||||
// Returns an error if something bad happens, user is responsible to catch it.
|
// Returns an error if something bad happens, user is responsible to catch it.
|
||||||
func (s *AmberEngine) Load() error {
|
func (s *AmberEngine) Load() error {
|
||||||
return walk(s.fs, s.rootDir, func(path string, info os.FileInfo, err error) error {
|
return walk(s.fs, "", func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ func WrapBlocks(v *blocks.Blocks) *BlocksEngine {
|
||||||
// Usage:
|
// Usage:
|
||||||
// Blocks("./views", ".html") or
|
// Blocks("./views", ".html") or
|
||||||
// Blocks(iris.Dir("./views"), ".html") or
|
// Blocks(iris.Dir("./views"), ".html") or
|
||||||
// Blocks(AssetFile(), ".html") for embedded data.
|
// Blocks(embed.FS, ".html") or Blocks(AssetFile(), ".html") for embedded data.
|
||||||
func Blocks(fs interface{}, extension string) *BlocksEngine {
|
func Blocks(fs interface{}, extension string) *BlocksEngine {
|
||||||
return WrapBlocks(blocks.New(fs).Extension(extension))
|
return WrapBlocks(blocks.New(fs).Extension(extension))
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ func (s *BlocksEngine) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RootDir sets the directory to use as the root one inside the provided File System.
|
// RootDir sets the directory to use as the root one inside the provided File System.
|
||||||
func (s *BlocksEngine) RootDir(root string) *BlocksEngine {
|
func (s *BlocksEngine) RootDir(root string) *BlocksEngine { // TODO: update blocks for the new fs.FS interface and use it for Sub.
|
||||||
s.Engine.RootDir(root)
|
s.Engine.RootDir(root)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package view
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
stdPath "path"
|
stdPath "path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -62,7 +62,7 @@ var AsSafeValue = pongo2.AsSafeValue
|
||||||
|
|
||||||
type tDjangoAssetLoader struct {
|
type tDjangoAssetLoader struct {
|
||||||
rootDir string
|
rootDir string
|
||||||
fs http.FileSystem
|
fs fs.FS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abs calculates the path to a given template. Whenever a path must be resolved
|
// Abs calculates the path to a given template. Whenever a path must be resolved
|
||||||
|
@ -91,7 +91,7 @@ func (l *tDjangoAssetLoader) Get(path string) (io.Reader, error) {
|
||||||
|
|
||||||
// DjangoEngine contains the django view engine structure.
|
// DjangoEngine contains the django view engine structure.
|
||||||
type DjangoEngine struct {
|
type DjangoEngine struct {
|
||||||
fs http.FileSystem
|
fs fs.FS
|
||||||
// files configuration
|
// files configuration
|
||||||
rootDir string
|
rootDir string
|
||||||
extension string
|
extension string
|
||||||
|
@ -117,7 +117,7 @@ var (
|
||||||
// Usage:
|
// Usage:
|
||||||
// Django("./views", ".html") or
|
// Django("./views", ".html") or
|
||||||
// Django(iris.Dir("./views"), ".html") or
|
// Django(iris.Dir("./views"), ".html") or
|
||||||
// Django(AssetFile(), ".html") for embedded data.
|
// Django(embed.FS, ".html") or Django(AssetFile(), ".html") for embedded data.
|
||||||
func Django(fs interface{}, extension string) *DjangoEngine {
|
func Django(fs interface{}, extension string) *DjangoEngine {
|
||||||
s := &DjangoEngine{
|
s := &DjangoEngine{
|
||||||
fs: getFS(fs),
|
fs: getFS(fs),
|
||||||
|
@ -134,6 +134,15 @@ func Django(fs interface{}, extension string) *DjangoEngine {
|
||||||
// RootDir sets the directory to be used as a starting point
|
// RootDir sets the directory to be used as a starting point
|
||||||
// to load templates from the provided file system.
|
// to load templates from the provided file system.
|
||||||
func (s *DjangoEngine) RootDir(root string) *DjangoEngine {
|
func (s *DjangoEngine) RootDir(root string) *DjangoEngine {
|
||||||
|
if s.fs != nil && root != "" && root != "/" && root != "." && root != s.rootDir {
|
||||||
|
sub, err := fs.Sub(s.fs, s.rootDir)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.fs = sub // here so the "middleware" can work.
|
||||||
|
}
|
||||||
|
|
||||||
s.rootDir = filepath.ToSlash(root)
|
s.rootDir = filepath.ToSlash(root)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -213,7 +222,7 @@ func (s *DjangoEngine) RegisterTag(tagName string, fn TagParser) error {
|
||||||
//
|
//
|
||||||
// Returns an error if something bad happens, user is responsible to catch it.
|
// Returns an error if something bad happens, user is responsible to catch it.
|
||||||
func (s *DjangoEngine) Load() error {
|
func (s *DjangoEngine) Load() error {
|
||||||
return walk(s.fs, s.rootDir, func(path string, info os.FileInfo, err error) error {
|
return walk(s.fs, "", func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
127
view/fs.go
127
view/fs.go
|
@ -2,125 +2,54 @@ package view
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io/fs"
|
||||||
"net/http"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/kataras/iris/v12/context"
|
"github.com/kataras/iris/v12/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// walk recursively in "fs" descends "root" path, calling "walkFn".
|
// walk recursively in "fileSystem" descends "root" path, calling "walkFn".
|
||||||
func walk(fs http.FileSystem, root string, walkFn filepath.WalkFunc) error {
|
func walk(fileSystem fs.FS, root string, walkFn filepath.WalkFunc) error {
|
||||||
names, err := assetNames(fs, root)
|
if root != "" && root != "/" && root != "." {
|
||||||
|
sub, err := fs.Sub(fileSystem, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %w", root, err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range names {
|
fileSystem = sub
|
||||||
fullpath := path.Join(root, name)
|
|
||||||
f, err := fs.Open(fullpath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %w", fullpath, err)
|
|
||||||
}
|
}
|
||||||
stat, err := f.Stat()
|
|
||||||
err = walkFn(fullpath, stat, err)
|
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", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := d.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != filepath.SkipDir {
|
if err != filepath.SkipDir {
|
||||||
return fmt.Errorf("%s: %w", fullpath, err)
|
return fmt.Errorf("%s: %w", path, err)
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if stat.IsDir() {
|
|
||||||
if err := walk(fs, fullpath, walkFn); err != nil {
|
|
||||||
return fmt.Errorf("%s: %w", fullpath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// assetNames returns the first-level directories and file, sorted, names.
|
if info.IsDir() {
|
||||||
func assetNames(fs http.FileSystem, name string) ([]string, error) {
|
return nil
|
||||||
f, err := fs.Open(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if f == nil {
|
return walkFn(path, info, err)
|
||||||
return nil, nil
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infos, err := f.Readdir(-1)
|
func asset(fileSystem fs.FS, name string) ([]byte, error) {
|
||||||
f.Close()
|
return fs.ReadFile(fileSystem, name)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
names := make([]string, 0, len(infos))
|
func getFS(fsOrDir interface{}) fs.FS {
|
||||||
for _, info := range infos {
|
return context.ResolveFS(fsOrDir)
|
||||||
// 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(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))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
// HandlebarsEngine contains the handlebars view engine structure.
|
// HandlebarsEngine contains the handlebars view engine structure.
|
||||||
type HandlebarsEngine struct {
|
type HandlebarsEngine struct {
|
||||||
fs http.FileSystem
|
fs fs.FS
|
||||||
// files configuration
|
// files configuration
|
||||||
rootDir string
|
rootDir string
|
||||||
extension string
|
extension string
|
||||||
|
@ -41,7 +41,7 @@ var (
|
||||||
// Usage:
|
// Usage:
|
||||||
// Handlebars("./views", ".html") or
|
// Handlebars("./views", ".html") or
|
||||||
// Handlebars(iris.Dir("./views"), ".html") or
|
// Handlebars(iris.Dir("./views"), ".html") or
|
||||||
// Handlebars(AssetFile(), ".html") for embedded data.
|
// Handlebars(embed.FS, ".html") or Handlebars(AssetFile(), ".html") for embedded data.
|
||||||
func Handlebars(fs interface{}, extension string) *HandlebarsEngine {
|
func Handlebars(fs interface{}, extension string) *HandlebarsEngine {
|
||||||
s := &HandlebarsEngine{
|
s := &HandlebarsEngine{
|
||||||
fs: getFS(fs),
|
fs: getFS(fs),
|
||||||
|
@ -66,6 +66,15 @@ func Handlebars(fs interface{}, extension string) *HandlebarsEngine {
|
||||||
// RootDir sets the directory to be used as a starting point
|
// RootDir sets the directory to be used as a starting point
|
||||||
// to load templates from the provided file system.
|
// to load templates from the provided file system.
|
||||||
func (s *HandlebarsEngine) RootDir(root string) *HandlebarsEngine {
|
func (s *HandlebarsEngine) RootDir(root string) *HandlebarsEngine {
|
||||||
|
if s.fs != nil && root != "" && root != "/" && root != "." && root != s.rootDir {
|
||||||
|
sub, err := fs.Sub(s.fs, s.rootDir)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.fs = sub // here so the "middleware" can work.
|
||||||
|
}
|
||||||
|
|
||||||
s.rootDir = filepath.ToSlash(root)
|
s.rootDir = filepath.ToSlash(root)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -125,7 +134,7 @@ func (s *HandlebarsEngine) AddGlobalFunc(funcName string, funcBody interface{})
|
||||||
//
|
//
|
||||||
// Returns an error if something bad happens, user is responsible to catch it.
|
// Returns an error if something bad happens, user is responsible to catch it.
|
||||||
func (s *HandlebarsEngine) Load() error {
|
func (s *HandlebarsEngine) Load() error {
|
||||||
return walk(s.fs, s.rootDir, func(path string, info os.FileInfo, _ error) error {
|
return walk(s.fs, "", func(path string, info os.FileInfo, _ error) error {
|
||||||
if info == nil || info.IsDir() {
|
if info == nil || info.IsDir() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
31
view/html.go
31
view/html.go
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -16,7 +16,7 @@ import (
|
||||||
type HTMLEngine struct {
|
type HTMLEngine struct {
|
||||||
name string // the view engine's name, can be HTML, Ace or Pug.
|
name string // the view engine's name, can be HTML, Ace or Pug.
|
||||||
// the file system to load from.
|
// the file system to load from.
|
||||||
fs http.FileSystem
|
fs fs.FS
|
||||||
// files configuration
|
// files configuration
|
||||||
rootDir string
|
rootDir string
|
||||||
extension string
|
extension string
|
||||||
|
@ -80,11 +80,11 @@ var emptyFuncs = template.FuncMap{
|
||||||
// Usage:
|
// Usage:
|
||||||
// HTML("./views", ".html") or
|
// HTML("./views", ".html") or
|
||||||
// HTML(iris.Dir("./views"), ".html") or
|
// HTML(iris.Dir("./views"), ".html") or
|
||||||
// HTML(AssetFile(), ".html") for embedded data.
|
// HTML(embed.FS, ".html") or HTML(AssetFile(), ".html") for embedded data.
|
||||||
func HTML(fs interface{}, extension string) *HTMLEngine {
|
func HTML(dirOrFS interface{}, extension string) *HTMLEngine {
|
||||||
s := &HTMLEngine{
|
s := &HTMLEngine{
|
||||||
name: "HTML",
|
name: "HTML",
|
||||||
fs: getFS(fs),
|
fs: getFS(dirOrFS),
|
||||||
rootDir: "/",
|
rootDir: "/",
|
||||||
extension: extension,
|
extension: extension,
|
||||||
reload: false,
|
reload: false,
|
||||||
|
@ -104,6 +104,15 @@ func HTML(fs interface{}, extension string) *HTMLEngine {
|
||||||
// RootDir sets the directory to be used as a starting point
|
// RootDir sets the directory to be used as a starting point
|
||||||
// to load templates from the provided file system.
|
// to load templates from the provided file system.
|
||||||
func (s *HTMLEngine) RootDir(root string) *HTMLEngine {
|
func (s *HTMLEngine) RootDir(root string) *HTMLEngine {
|
||||||
|
if s.fs != nil && root != "" && root != "/" && root != "." && root != s.rootDir {
|
||||||
|
sub, err := fs.Sub(s.fs, root)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.fs = sub // here so the "middleware" can work.
|
||||||
|
}
|
||||||
|
|
||||||
s.rootDir = filepath.ToSlash(root)
|
s.rootDir = filepath.ToSlash(root)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -246,7 +255,7 @@ func (s *HTMLEngine) load() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return walk(s.fs, s.rootDir, func(path string, info os.FileInfo, err error) error {
|
err := walk(s.fs, "", func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -268,6 +277,16 @@ func (s *HTMLEngine) load() error {
|
||||||
|
|
||||||
return s.parseTemplate(path, buf, nil)
|
return s.parseTemplate(path, buf, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Templates == nil {
|
||||||
|
return fmt.Errorf("no templates found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HTMLEngine) reloadCustomTemplates() error {
|
func (s *HTMLEngine) reloadCustomTemplates() error {
|
||||||
|
|
27
view/jet.go
27
view/jet.go
|
@ -3,7 +3,7 @@ package view
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -19,7 +19,7 @@ const jetEngineName = "jet"
|
||||||
|
|
||||||
// JetEngine is the jet template parser's view engine.
|
// JetEngine is the jet template parser's view engine.
|
||||||
type JetEngine struct {
|
type JetEngine struct {
|
||||||
fs http.FileSystem
|
fs fs.FS
|
||||||
rootDir string
|
rootDir string
|
||||||
extension string
|
extension string
|
||||||
left, right string
|
left, right string
|
||||||
|
@ -59,8 +59,8 @@ var jetExtensions = [...]string{
|
||||||
// Usage:
|
// Usage:
|
||||||
// Jet("./views", ".jet") or
|
// Jet("./views", ".jet") or
|
||||||
// Jet(iris.Dir("./views"), ".jet") or
|
// Jet(iris.Dir("./views"), ".jet") or
|
||||||
// Jet(AssetFile(), ".jet") for embedded data.
|
// Jet(embed.FS, ".jet") or Jet(AssetFile(), ".jet") for embedded data.
|
||||||
func Jet(fs interface{}, extension string) *JetEngine {
|
func Jet(dirOrFS interface{}, extension string) *JetEngine {
|
||||||
extOK := false
|
extOK := false
|
||||||
for _, ext := range jetExtensions {
|
for _, ext := range jetExtensions {
|
||||||
if ext == extension {
|
if ext == extension {
|
||||||
|
@ -74,10 +74,10 @@ func Jet(fs interface{}, extension string) *JetEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &JetEngine{
|
s := &JetEngine{
|
||||||
fs: getFS(fs),
|
fs: getFS(dirOrFS),
|
||||||
rootDir: "/",
|
rootDir: "/",
|
||||||
extension: extension,
|
extension: extension,
|
||||||
loader: &jetLoader{fs: getFS(fs)},
|
loader: &jetLoader{fs: getFS(dirOrFS)},
|
||||||
jetDataContextKey: "_jet",
|
jetDataContextKey: "_jet",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +92,15 @@ func (s *JetEngine) String() string {
|
||||||
// RootDir sets the directory to be used as a starting point
|
// RootDir sets the directory to be used as a starting point
|
||||||
// to load templates from the provided file system.
|
// to load templates from the provided file system.
|
||||||
func (s *JetEngine) RootDir(root string) *JetEngine {
|
func (s *JetEngine) RootDir(root string) *JetEngine {
|
||||||
|
if s.fs != nil && root != "" && root != "/" && root != "." && root != s.rootDir {
|
||||||
|
sub, err := fs.Sub(s.fs, s.rootDir)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.fs = sub
|
||||||
|
}
|
||||||
|
|
||||||
s.rootDir = filepath.ToSlash(root)
|
s.rootDir = filepath.ToSlash(root)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -199,7 +208,7 @@ func (s *JetEngine) SetLoader(loader jet.Loader) *JetEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
type jetLoader struct {
|
type jetLoader struct {
|
||||||
fs http.FileSystem
|
fs fs.FS
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ jet.Loader = (*jetLoader)(nil)
|
var _ jet.Loader = (*jetLoader)(nil)
|
||||||
|
@ -217,7 +226,7 @@ func (l *jetLoader) Exists(name string) bool {
|
||||||
|
|
||||||
// Load should load the templates from a physical system directory or by an embedded one (assets/go-bindata).
|
// Load should load the templates from a physical system directory or by an embedded one (assets/go-bindata).
|
||||||
func (s *JetEngine) Load() error {
|
func (s *JetEngine) Load() error {
|
||||||
return walk(s.fs, s.rootDir, func(path string, info os.FileInfo, err error) error {
|
return walk(s.fs, "", func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -256,7 +265,7 @@ func (s *JetEngine) initSet() {
|
||||||
var opts = []jet.Option{
|
var opts = []jet.Option{
|
||||||
jet.WithDelims(s.left, s.right),
|
jet.WithDelims(s.left, s.right),
|
||||||
}
|
}
|
||||||
if s.developmentMode && !isNoOpFS(s.fs) {
|
if s.developmentMode && !context.IsNoOpFS(s.fs) {
|
||||||
// this check is made to avoid jet's fs lookup on noOp fs (nil passed by the developer).
|
// this check is made to avoid jet's fs lookup on noOp fs (nil passed by the developer).
|
||||||
// This can be produced when nil fs passed
|
// This can be produced when nil fs passed
|
||||||
// and only `ParseTemplate` is used.
|
// and only `ParseTemplate` is used.
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
// Usage:
|
// Usage:
|
||||||
// Pug("./views", ".pug") or
|
// Pug("./views", ".pug") or
|
||||||
// Pug(iris.Dir("./views"), ".pug") or
|
// Pug(iris.Dir("./views"), ".pug") or
|
||||||
// Pug(AssetFile(), ".pug") for embedded data.
|
// Pug(embed.FS, ".pug") or Pug(AssetFile(), ".pug") for embedded data.
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
// https://github.com/kataras/iris/tree/master/_examples/view/template_pug_0
|
// https://github.com/kataras/iris/tree/master/_examples/view/template_pug_0
|
||||||
|
|
Loading…
Reference in New Issue
Block a user