mark2web/vendor/github.com/flosch/pongo2/v4/template_loader.go
Sebastian Frank a781485c0a
Some checks failed
continuous-integration/drone/push Build is failing
no git submodules
2022-02-28 10:28:34 +01:00

214 lines
6.0 KiB
Go

package pongo2
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
)
// LocalFilesystemLoader represents a local filesystem loader with basic
// BaseDirectory capabilities. The access to the local filesystem is unrestricted.
type LocalFilesystemLoader struct {
baseDir string
}
// MustNewLocalFileSystemLoader creates a new LocalFilesystemLoader instance
// and panics if there's any error during instantiation. The parameters
// are the same like NewLocalFileSystemLoader.
func MustNewLocalFileSystemLoader(baseDir string) *LocalFilesystemLoader {
fs, err := NewLocalFileSystemLoader(baseDir)
if err != nil {
log.Panic(err)
}
return fs
}
// NewLocalFileSystemLoader creates a new LocalFilesystemLoader and allows
// templatesto be loaded from disk (unrestricted). If any base directory
// is given (or being set using SetBaseDir), this base directory is being used
// for path calculation in template inclusions/imports. Otherwise the path
// is calculated based relatively to the including template's path.
func NewLocalFileSystemLoader(baseDir string) (*LocalFilesystemLoader, error) {
fs := &LocalFilesystemLoader{}
if baseDir != "" {
if err := fs.SetBaseDir(baseDir); err != nil {
return nil, err
}
}
return fs, nil
}
// SetBaseDir sets the template's base directory. This directory will
// be used for any relative path in filters, tags and From*-functions to determine
// your template. See the comment for NewLocalFileSystemLoader as well.
func (fs *LocalFilesystemLoader) SetBaseDir(path string) error {
// Make the path absolute
if !filepath.IsAbs(path) {
abs, err := filepath.Abs(path)
if err != nil {
return err
}
path = abs
}
// Check for existence
fi, err := os.Stat(path)
if err != nil {
return err
}
if !fi.IsDir() {
return fmt.Errorf("The given path '%s' is not a directory.", path)
}
fs.baseDir = path
return nil
}
// Get reads the path's content from your local filesystem.
func (fs *LocalFilesystemLoader) Get(path string) (io.Reader, error) {
buf, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return bytes.NewReader(buf), nil
}
// Abs resolves a filename relative to the base directory. Absolute paths are allowed.
// When there's no base dir set, the absolute path to the filename
// will be calculated based on either the provided base directory (which
// might be a path of a template which includes another template) or
// the current working directory.
func (fs *LocalFilesystemLoader) Abs(base, name string) string {
if filepath.IsAbs(name) {
return name
}
// Our own base dir has always priority; if there's none
// we use the path provided in base.
var err error
if fs.baseDir == "" {
if base == "" {
base, err = os.Getwd()
if err != nil {
panic(err)
}
return filepath.Join(base, name)
}
return filepath.Join(filepath.Dir(base), name)
}
return filepath.Join(fs.baseDir, name)
}
// SandboxedFilesystemLoader is still WIP.
type SandboxedFilesystemLoader struct {
*LocalFilesystemLoader
}
// NewSandboxedFilesystemLoader creates a new sandboxed local file system instance.
func NewSandboxedFilesystemLoader(baseDir string) (*SandboxedFilesystemLoader, error) {
fs, err := NewLocalFileSystemLoader(baseDir)
if err != nil {
return nil, err
}
return &SandboxedFilesystemLoader{
LocalFilesystemLoader: fs,
}, nil
}
// Move sandbox to a virtual fs
/*
if len(set.SandboxDirectories) > 0 {
defer func() {
// Remove any ".." or other crap
resolvedPath = filepath.Clean(resolvedPath)
// Make the path absolute
absPath, err := filepath.Abs(resolvedPath)
if err != nil {
panic(err)
}
resolvedPath = absPath
// Check against the sandbox directories (once one pattern matches, we're done and can allow it)
for _, pattern := range set.SandboxDirectories {
matched, err := filepath.Match(pattern, resolvedPath)
if err != nil {
panic("Wrong sandbox directory match pattern (see http://golang.org/pkg/path/filepath/#Match).")
}
if matched {
// OK!
return
}
}
// No pattern matched, we have to log+deny the request
set.logf("Access attempt outside of the sandbox directories (blocked): '%s'", resolvedPath)
resolvedPath = ""
}()
}
*/
// HttpFilesystemLoader supports loading templates
// from an http.FileSystem - useful for using one of several
// file-to-code generators that packs static files into
// a go binary (ex: https://github.com/jteeuwen/go-bindata)
type HttpFilesystemLoader struct {
fs http.FileSystem
baseDir string
}
// MustNewHttpFileSystemLoader creates a new HttpFilesystemLoader instance
// and panics if there's any error during instantiation. The parameters
// are the same like NewHttpFilesystemLoader.
func MustNewHttpFileSystemLoader(httpfs http.FileSystem, baseDir string) *HttpFilesystemLoader {
fs, err := NewHttpFileSystemLoader(httpfs, baseDir)
if err != nil {
log.Panic(err)
}
return fs
}
// NewHttpFileSystemLoader creates a new HttpFileSystemLoader and allows
// templates to be loaded from the virtual filesystem. The path
// is calculated based relatively from the root of the http.Filesystem.
func NewHttpFileSystemLoader(httpfs http.FileSystem, baseDir string) (*HttpFilesystemLoader, error) {
hfs := &HttpFilesystemLoader{
fs: httpfs,
baseDir: baseDir,
}
if httpfs == nil {
err := errors.New("httpfs cannot be nil")
return nil, err
}
return hfs, nil
}
// Abs in this instance simply returns the filename, since
// there's no potential for an unexpanded path in an http.FileSystem
func (h *HttpFilesystemLoader) Abs(base, name string) string {
return name
}
// Get returns an io.Reader where the template's content can be read from.
func (h *HttpFilesystemLoader) Get(path string) (io.Reader, error) {
fullPath := path
if h.baseDir != "" {
fullPath = fmt.Sprintf(
"%s/%s",
h.baseDir,
fullPath,
)
}
return h.fs.Open(fullPath)
}