mirror of
https://github.com/Luzifer/promcertcheck.git
synced 2024-11-09 16:30:04 +00:00
Force latest version of pongo2
v3 has a bug with sorted keyword Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
18716269e1
commit
2f67c05f2e
94 changed files with 4386 additions and 1265 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
certcheck
|
certcheck
|
||||||
|
promcertcheck
|
||||||
|
|
12
Gopkg.lock
generated
12
Gopkg.lock
generated
|
@ -14,10 +14,10 @@
|
||||||
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
|
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/flosch/pongo2"
|
name = "github.com/flosch/pongo2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "5e81b817a0c48c1c57cdf1a9056cf76bdee02ca9"
|
revision = "1f4be1efe3b3529b7e58861f75d70120a9567dc4"
|
||||||
version = "v3.0"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -37,6 +37,12 @@
|
||||||
revision = "24fca303ac6da784b9e8269f724ddeb0b2eea5e7"
|
revision = "24fca303ac6da784b9e8269f724ddeb0b2eea5e7"
|
||||||
version = "v1.5.0"
|
version = "v1.5.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/juju/errors"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "c7d06af17c68cd34c835053720b21f6549d9b0ee"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||||
packages = ["pbutil"]
|
packages = ["pbutil"]
|
||||||
|
@ -112,6 +118,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "d0a90698569f49d4e7ef58586b857a1c7c60e48eaca07f1585d02e7ce91ca092"
|
inputs-digest = "f88f786b9ff5e99b5589aea171923fd8d9dcef123a4d6be68d7659b923e8dc1e"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/flosch/pongo2"
|
name = "github.com/flosch/pongo2"
|
||||||
|
branch = "master"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/gorilla/mux"
|
name = "github.com/gorilla/mux"
|
||||||
|
|
BIN
promcertcheck
BIN
promcertcheck
Binary file not shown.
1
vendor/github.com/flosch/pongo2/.gitignore
generated
vendored
1
vendor/github.com/flosch/pongo2/.gitignore
generated
vendored
|
@ -7,6 +7,7 @@
|
||||||
_obj
|
_obj
|
||||||
_test
|
_test
|
||||||
.idea
|
.idea
|
||||||
|
.vscode
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
# Architecture specific extensions/prefixes
|
||||||
*.[568vq]
|
*.[568vq]
|
||||||
|
|
5
vendor/github.com/flosch/pongo2/.travis.yml
generated
vendored
5
vendor/github.com/flosch/pongo2/.travis.yml
generated
vendored
|
@ -1,12 +1,13 @@
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.3
|
- 1.7
|
||||||
- tip
|
- tip
|
||||||
install:
|
install:
|
||||||
- go get code.google.com/p/go.tools/cmd/cover
|
- go get golang.org/x/tools/cmd/cover
|
||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
- go get gopkg.in/check.v1
|
- go get gopkg.in/check.v1
|
||||||
|
- go get github.com/juju/errors
|
||||||
script:
|
script:
|
||||||
- go test -v -covermode=count -coverprofile=coverage.out -bench . -cpu 1,4
|
- go test -v -covermode=count -coverprofile=coverage.out -bench . -cpu 1,4
|
||||||
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken $COVERALLS_TOKEN || true'
|
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken $COVERALLS_TOKEN || true'
|
||||||
|
|
15
vendor/github.com/flosch/pongo2/README.md
generated
vendored
15
vendor/github.com/flosch/pongo2/README.md
generated
vendored
|
@ -1,8 +1,9 @@
|
||||||
# [pongo](https://en.wikipedia.org/wiki/Pongo_%28genus%29)2
|
# [pongo](https://en.wikipedia.org/wiki/Pongo_%28genus%29)2
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/flosch/pongo2?status.png)](https://godoc.org/github.com/flosch/pongo2)
|
[![Join the chat at https://gitter.im/flosch/pongo2](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/flosch/pongo2)
|
||||||
|
[![GoDoc](https://godoc.org/github.com/flosch/pongo2?status.svg)](https://godoc.org/github.com/flosch/pongo2)
|
||||||
[![Build Status](https://travis-ci.org/flosch/pongo2.svg?branch=master)](https://travis-ci.org/flosch/pongo2)
|
[![Build Status](https://travis-ci.org/flosch/pongo2.svg?branch=master)](https://travis-ci.org/flosch/pongo2)
|
||||||
[![Coverage Status](https://coveralls.io/repos/flosch/pongo2/badge.png?branch=master)](https://coveralls.io/r/flosch/pongo2?branch=master)
|
[![Coverage Status](https://coveralls.io/repos/flosch/pongo2/badge.svg?branch=master)](https://coveralls.io/r/flosch/pongo2?branch=master)
|
||||||
[![gratipay](http://img.shields.io/badge/gratipay-support%20pongo-brightgreen.svg)](https://gratipay.com/flosch/)
|
[![gratipay](http://img.shields.io/badge/gratipay-support%20pongo-brightgreen.svg)](https://gratipay.com/flosch/)
|
||||||
[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=3654947)](https://www.bountysource.com/trackers/3654947-pongo2?utm_source=3654947&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=3654947)](https://www.bountysource.com/trackers/3654947-pongo2?utm_source=3654947&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||||
|
|
||||||
|
@ -95,6 +96,7 @@ Please also have a look on the [caveats](https://github.com/flosch/pongo2#caveat
|
||||||
|
|
||||||
If you're using the `master`-branch of pongo2, you might be interested in this section. Since pongo2 is still in development (even though there is a first stable release!), there could be (backwards-incompatible) API changes over time. To keep track of these and therefore make it painless for you to adapt your codebase, I'll list them here.
|
If you're using the `master`-branch of pongo2, you might be interested in this section. Since pongo2 is still in development (even though there is a first stable release!), there could be (backwards-incompatible) API changes over time. To keep track of these and therefore make it painless for you to adapt your codebase, I'll list them here.
|
||||||
|
|
||||||
|
* Function signature for tag execution changed: not taking a `bytes.Buffer` anymore; instead `Execute()`-functions are now taking a `TemplateWriter` interface.
|
||||||
* Function signature for tag and filter parsing/execution changed (`error` return type changed to `*Error`).
|
* Function signature for tag and filter parsing/execution changed (`error` return type changed to `*Error`).
|
||||||
* `INodeEvaluator` has been removed and got replaced by `IEvaluator`. You can change your existing tags/filters by simply replacing the interface.
|
* `INodeEvaluator` has been removed and got replaced by `IEvaluator`. You can change your existing tags/filters by simply replacing the interface.
|
||||||
* Two new helper functions: [`RenderTemplateFile()`](https://godoc.org/github.com/flosch/pongo2#RenderTemplateFile) and [`RenderTemplateString()`](https://godoc.org/github.com/flosch/pongo2#RenderTemplateString).
|
* Two new helper functions: [`RenderTemplateFile()`](https://godoc.org/github.com/flosch/pongo2#RenderTemplateFile) and [`RenderTemplateString()`](https://godoc.org/github.com/flosch/pongo2#RenderTemplateString).
|
||||||
|
@ -104,7 +106,7 @@ If you're using the `master`-branch of pongo2, you might be interested in this s
|
||||||
## How you can help
|
## How you can help
|
||||||
|
|
||||||
* Write [filters](https://github.com/flosch/pongo2/blob/master/filters_builtin.go#L3) / [tags](https://github.com/flosch/pongo2/blob/master/tags.go#L4) (see [tutorial](https://www.florian-schlachter.de/post/pongo2/)) by forking pongo2 and sending pull requests
|
* Write [filters](https://github.com/flosch/pongo2/blob/master/filters_builtin.go#L3) / [tags](https://github.com/flosch/pongo2/blob/master/tags.go#L4) (see [tutorial](https://www.florian-schlachter.de/post/pongo2/)) by forking pongo2 and sending pull requests
|
||||||
* Write/improve code tests (use the following command to see what tests are missing: `go test -v -cover -covermode=count -coverprofile=cover.out && go tool cover -html=cover.out`)
|
* Write/improve code tests (use the following command to see what tests are missing: `go test -v -cover -covermode=count -coverprofile=cover.out && go tool cover -html=cover.out` or have a look on [gocover.io/github.com/flosch/pongo2](http://gocover.io/github.com/flosch/pongo2))
|
||||||
* Write/improve template tests (see the `template_tests/` directory)
|
* Write/improve template tests (see the `template_tests/` directory)
|
||||||
* Write middleware, libraries and websites using pongo2. :-)
|
* Write middleware, libraries and websites using pongo2. :-)
|
||||||
|
|
||||||
|
@ -116,6 +118,7 @@ You can access pongo2's API documentation on [godoc](https://godoc.org/github.co
|
||||||
|
|
||||||
## Blog post series
|
## Blog post series
|
||||||
|
|
||||||
|
* [pongo2 v3 released](https://www.florian-schlachter.de/post/pongo2-v3/)
|
||||||
* [pongo2 v2 released](https://www.florian-schlachter.de/post/pongo2-v2/)
|
* [pongo2 v2 released](https://www.florian-schlachter.de/post/pongo2-v2/)
|
||||||
* [pongo2 1.0 released](https://www.florian-schlachter.de/post/pongo2-10/) [August 8th 2014]
|
* [pongo2 1.0 released](https://www.florian-schlachter.de/post/pongo2-10/) [August 8th 2014]
|
||||||
* [pongo2 playground](https://www.florian-schlachter.de/post/pongo2-playground/) [August 1st 2014]
|
* [pongo2 playground](https://www.florian-schlachter.de/post/pongo2-playground/) [August 1st 2014]
|
||||||
|
@ -154,7 +157,11 @@ You can access pongo2's API documentation on [godoc](https://godoc.org/github.co
|
||||||
* [beego-pongo2.v2](https://github.com/ipfans/beego-pongo2.v2) - Same as `beego-pongo2`, but for pongo2 v2.
|
* [beego-pongo2.v2](https://github.com/ipfans/beego-pongo2.v2) - Same as `beego-pongo2`, but for pongo2 v2.
|
||||||
* [macaron-pongo2](https://github.com/macaron-contrib/pongo2) - pongo2 support for [Macaron](https://github.com/Unknwon/macaron), a modular web framework.
|
* [macaron-pongo2](https://github.com/macaron-contrib/pongo2) - pongo2 support for [Macaron](https://github.com/Unknwon/macaron), a modular web framework.
|
||||||
* [ginpongo2](https://github.com/ngerakines/ginpongo2) - middleware for [gin](github.com/gin-gonic/gin) to use pongo2 templates
|
* [ginpongo2](https://github.com/ngerakines/ginpongo2) - middleware for [gin](github.com/gin-gonic/gin) to use pongo2 templates
|
||||||
* [pongo2-trans](https://github.com/fromYukki/pongo2trans) - `trans`-tag implementation for internationalization
|
* [Build'n support for Iris' template engine](https://github.com/kataras/iris)
|
||||||
|
* [pongo2gin](https://github.com/robvdl/pongo2gin) - alternative renderer for [gin](github.com/gin-gonic/gin) to use pongo2 templates
|
||||||
|
* [pongo2-trans](https://github.com/digitalcrab/pongo2trans) - `trans`-tag implementation for internationalization
|
||||||
|
* [tpongo2](https://github.com/tango-contrib/tpongo2) - pongo2 support for [Tango](https://github.com/lunny/tango), a micro-kernel & pluggable web framework.
|
||||||
|
* [p2cli](https://github.com/wrouesnel/p2cli) - command line templating utility based on pongo2
|
||||||
|
|
||||||
Please add your project to this list and send me a pull request when you've developed something nice for pongo2.
|
Please add your project to this list and send me a pull request when you've developed something nice for pongo2.
|
||||||
|
|
||||||
|
|
16
vendor/github.com/flosch/pongo2/context.go
generated
vendored
16
vendor/github.com/flosch/pongo2/context.go
generated
vendored
|
@ -1,13 +1,14 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$")
|
var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$")
|
||||||
|
|
||||||
// Use this Context type to provide constants, variables, instances or functions to your template.
|
// A Context type provides constants, variables, instances or functions to a template.
|
||||||
//
|
//
|
||||||
// pongo2 automatically provides meta-information or functions through the "pongo2"-key.
|
// pongo2 automatically provides meta-information or functions through the "pongo2"-key.
|
||||||
// Currently, context["pongo2"] contains the following keys:
|
// Currently, context["pongo2"] contains the following keys:
|
||||||
|
@ -25,13 +26,14 @@ func (c Context) checkForValidIdentifiers() *Error {
|
||||||
if !reIdentifiers.MatchString(k) {
|
if !reIdentifiers.MatchString(k) {
|
||||||
return &Error{
|
return &Error{
|
||||||
Sender: "checkForValidIdentifiers",
|
Sender: "checkForValidIdentifiers",
|
||||||
ErrorMsg: fmt.Sprintf("Context-key '%s' (value: '%+v') is not a valid identifier.", k, v),
|
OrigError: errors.Errorf("context-key '%s' (value: '%+v') is not a valid identifier", k, v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update updates this context with the key/value-pairs from another context.
|
||||||
func (c Context) Update(other Context) Context {
|
func (c Context) Update(other Context) Context {
|
||||||
for k, v := range other {
|
for k, v := range other {
|
||||||
c[k] = v
|
c[k] = v
|
||||||
|
@ -39,6 +41,8 @@ func (c Context) Update(other Context) Context {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecutionContext contains all data important for the current rendering state.
|
||||||
|
//
|
||||||
// If you're writing a custom tag, your tag's Execute()-function will
|
// If you're writing a custom tag, your tag's Execute()-function will
|
||||||
// have access to the ExecutionContext. This struct stores anything
|
// have access to the ExecutionContext. This struct stores anything
|
||||||
// about the current rendering process's Context including
|
// about the current rendering process's Context including
|
||||||
|
@ -97,6 +101,10 @@ func NewChildExecutionContext(parent *ExecutionContext) *ExecutionContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
|
func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
|
||||||
|
return ctx.OrigError(errors.New(msg), token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *ExecutionContext) OrigError(err error, token *Token) *Error {
|
||||||
filename := ctx.template.name
|
filename := ctx.template.name
|
||||||
var line, col int
|
var line, col int
|
||||||
if token != nil {
|
if token != nil {
|
||||||
|
@ -113,7 +121,7 @@ func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
|
||||||
Column: col,
|
Column: col,
|
||||||
Token: token,
|
Token: token,
|
||||||
Sender: "execution",
|
Sender: "execution",
|
||||||
ErrorMsg: msg,
|
OrigError: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
25
vendor/github.com/flosch/pongo2/error.go
generated
vendored
25
vendor/github.com/flosch/pongo2/error.go
generated
vendored
|
@ -6,7 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This Error type is being used to address an error during lexing, parsing or
|
// The Error type is being used to address an error during lexing, parsing or
|
||||||
// execution. If you want to return an error object (for example in your own
|
// execution. If you want to return an error object (for example in your own
|
||||||
// tag or filter) fill this object with as much information as you have.
|
// tag or filter) fill this object with as much information as you have.
|
||||||
// Make sure "Sender" is always given (if you're returning an error within
|
// Make sure "Sender" is always given (if you're returning an error within
|
||||||
|
@ -19,7 +19,7 @@ type Error struct {
|
||||||
Column int
|
Column int
|
||||||
Token *Token
|
Token *Token
|
||||||
Sender string
|
Sender string
|
||||||
ErrorMsg string
|
OrigError error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Error) updateFromTokenIfNeeded(template *Template, t *Token) *Error {
|
func (e *Error) updateFromTokenIfNeeded(template *Template, t *Token) *Error {
|
||||||
|
@ -54,14 +54,14 @@ func (e *Error) Error() string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s += "] "
|
s += "] "
|
||||||
s += e.ErrorMsg
|
s += e.OrigError.Error()
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the affected line from the original template, if available.
|
// RawLine returns the affected line from the original template, if available.
|
||||||
func (e *Error) RawLine() (line string, available bool) {
|
func (e *Error) RawLine() (line string, available bool, outErr error) {
|
||||||
if e.Line <= 0 || e.Filename == "<string>" {
|
if e.Line <= 0 || e.Filename == "<string>" {
|
||||||
return "", false
|
return "", false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := e.Filename
|
filename := e.Filename
|
||||||
|
@ -70,17 +70,22 @@ func (e *Error) RawLine() (line string, available bool) {
|
||||||
}
|
}
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return "", false, err
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer func() {
|
||||||
|
err := file.Close()
|
||||||
|
if err != nil && outErr == nil {
|
||||||
|
outErr = err
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
scanner := bufio.NewScanner(file)
|
scanner := bufio.NewScanner(file)
|
||||||
l := 0
|
l := 0
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
l++
|
l++
|
||||||
if l == e.Line {
|
if l == e.Line {
|
||||||
return scanner.Text(), true
|
return scanner.Text(), true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false, nil
|
||||||
}
|
}
|
||||||
|
|
52
vendor/github.com/flosch/pongo2/filters.go
generated
vendored
52
vendor/github.com/flosch/pongo2/filters.go
generated
vendored
|
@ -2,8 +2,11 @@ package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FilterFunction is the type filter functions must fulfil
|
||||||
type FilterFunction func(in *Value, param *Value) (out *Value, err *Error)
|
type FilterFunction func(in *Value, param *Value) (out *Value, err *Error)
|
||||||
|
|
||||||
var filters map[string]FilterFunction
|
var filters map[string]FilterFunction
|
||||||
|
@ -12,32 +15,38 @@ func init() {
|
||||||
filters = make(map[string]FilterFunction)
|
filters = make(map[string]FilterFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registers a new filter. If there's already a filter with the same
|
// FilterExists returns true if the given filter is already registered
|
||||||
|
func FilterExists(name string) bool {
|
||||||
|
_, existing := filters[name]
|
||||||
|
return existing
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterFilter registers a new filter. If there's already a filter with the same
|
||||||
// name, RegisterFilter will panic. You usually want to call this
|
// name, RegisterFilter will panic. You usually want to call this
|
||||||
// function in the filter's init() function:
|
// function in the filter's init() function:
|
||||||
// http://golang.org/doc/effective_go.html#init
|
// http://golang.org/doc/effective_go.html#init
|
||||||
//
|
//
|
||||||
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
||||||
// writing filters and tags.
|
// writing filters and tags.
|
||||||
func RegisterFilter(name string, fn FilterFunction) {
|
func RegisterFilter(name string, fn FilterFunction) error {
|
||||||
_, existing := filters[name]
|
if FilterExists(name) {
|
||||||
if existing {
|
return errors.Errorf("filter with name '%s' is already registered", name)
|
||||||
panic(fmt.Sprintf("Filter with name '%s' is already registered.", name))
|
|
||||||
}
|
}
|
||||||
filters[name] = fn
|
filters[name] = fn
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces an already registered filter with a new implementation. Use this
|
// ReplaceFilter replaces an already registered filter with a new implementation. Use this
|
||||||
// function with caution since it allows you to change existing filter behaviour.
|
// function with caution since it allows you to change existing filter behaviour.
|
||||||
func ReplaceFilter(name string, fn FilterFunction) {
|
func ReplaceFilter(name string, fn FilterFunction) error {
|
||||||
_, existing := filters[name]
|
if !FilterExists(name) {
|
||||||
if !existing {
|
return errors.Errorf("filter with name '%s' does not exist (therefore cannot be overridden)", name)
|
||||||
panic(fmt.Sprintf("Filter with name '%s' does not exist (therefore cannot be overridden).", name))
|
|
||||||
}
|
}
|
||||||
filters[name] = fn
|
filters[name] = fn
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like ApplyFilter, but panics on an error
|
// MustApplyFilter behaves like ApplyFilter, but panics on an error.
|
||||||
func MustApplyFilter(name string, value *Value, param *Value) *Value {
|
func MustApplyFilter(name string, value *Value, param *Value) *Value {
|
||||||
val, err := ApplyFilter(name, value, param)
|
val, err := ApplyFilter(name, value, param)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -46,13 +55,14 @@ func MustApplyFilter(name string, value *Value, param *Value) *Value {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applies a filter to a given value using the given parameters. Returns a *pongo2.Value or an error.
|
// ApplyFilter applies a filter to a given value using the given parameters.
|
||||||
|
// Returns a *pongo2.Value or an error.
|
||||||
func ApplyFilter(name string, value *Value, param *Value) (*Value, *Error) {
|
func ApplyFilter(name string, value *Value, param *Value) (*Value, *Error) {
|
||||||
fn, existing := filters[name]
|
fn, existing := filters[name]
|
||||||
if !existing {
|
if !existing {
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Sender: "applyfilter",
|
Sender: "applyfilter",
|
||||||
ErrorMsg: fmt.Sprintf("Filter with name '%s' not found.", name),
|
OrigError: errors.Errorf("Filter with name '%s' not found.", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,31 +96,31 @@ func (fc *filterCall) Execute(v *Value, ctx *ExecutionContext) (*Value, *Error)
|
||||||
param = AsValue(nil)
|
param = AsValue(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
filtered_value, err := fc.filterFunc(v, param)
|
filteredValue, err := fc.filterFunc(v, param)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.updateFromTokenIfNeeded(ctx.template, fc.token)
|
return nil, err.updateFromTokenIfNeeded(ctx.template, fc.token)
|
||||||
}
|
}
|
||||||
return filtered_value, nil
|
return filteredValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter = IDENT | IDENT ":" FilterArg | IDENT "|" Filter
|
// Filter = IDENT | IDENT ":" FilterArg | IDENT "|" Filter
|
||||||
func (p *Parser) parseFilter() (*filterCall, *Error) {
|
func (p *Parser) parseFilter() (*filterCall, *Error) {
|
||||||
ident_token := p.MatchType(TokenIdentifier)
|
identToken := p.MatchType(TokenIdentifier)
|
||||||
|
|
||||||
// Check filter ident
|
// Check filter ident
|
||||||
if ident_token == nil {
|
if identToken == nil {
|
||||||
return nil, p.Error("Filter name must be an identifier.", nil)
|
return nil, p.Error("Filter name must be an identifier.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := &filterCall{
|
filter := &filterCall{
|
||||||
token: ident_token,
|
token: identToken,
|
||||||
name: ident_token.Val,
|
name: identToken.Val,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the appropriate filter function and bind it
|
// Get the appropriate filter function and bind it
|
||||||
filterFn, exists := filters[ident_token.Val]
|
filterFn, exists := filters[identToken.Val]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, p.Error(fmt.Sprintf("Filter '%s' does not exist.", ident_token.Val), ident_token)
|
return nil, p.Error(fmt.Sprintf("Filter '%s' does not exist.", identToken.Val), identToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
filter.filterFunc = filterFn
|
filter.filterFunc = filterFn
|
||||||
|
|
164
vendor/github.com/flosch/pongo2/filters_builtin.go
generated
vendored
164
vendor/github.com/flosch/pongo2/filters_builtin.go
generated
vendored
|
@ -35,6 +35,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -73,14 +75,15 @@ func init() {
|
||||||
RegisterFilter("removetags", filterRemovetags)
|
RegisterFilter("removetags", filterRemovetags)
|
||||||
RegisterFilter("rjust", filterRjust)
|
RegisterFilter("rjust", filterRjust)
|
||||||
RegisterFilter("slice", filterSlice)
|
RegisterFilter("slice", filterSlice)
|
||||||
|
RegisterFilter("split", filterSplit)
|
||||||
RegisterFilter("stringformat", filterStringformat)
|
RegisterFilter("stringformat", filterStringformat)
|
||||||
RegisterFilter("striptags", filterStriptags)
|
RegisterFilter("striptags", filterStriptags)
|
||||||
RegisterFilter("time", filterDate) // time uses filterDate (same golang-format)
|
RegisterFilter("time", filterDate) // time uses filterDate (same golang-format)
|
||||||
RegisterFilter("title", filterTitle)
|
RegisterFilter("title", filterTitle)
|
||||||
RegisterFilter("truncatechars", filterTruncatechars)
|
RegisterFilter("truncatechars", filterTruncatechars)
|
||||||
RegisterFilter("truncatechars_html", filterTruncatecharsHtml)
|
RegisterFilter("truncatechars_html", filterTruncatecharsHTML)
|
||||||
RegisterFilter("truncatewords", filterTruncatewords)
|
RegisterFilter("truncatewords", filterTruncatewords)
|
||||||
RegisterFilter("truncatewords_html", filterTruncatewordsHtml)
|
RegisterFilter("truncatewords_html", filterTruncatewordsHTML)
|
||||||
RegisterFilter("upper", filterUpper)
|
RegisterFilter("upper", filterUpper)
|
||||||
RegisterFilter("urlencode", filterUrlencode)
|
RegisterFilter("urlencode", filterUrlencode)
|
||||||
RegisterFilter("urlize", filterUrlize)
|
RegisterFilter("urlize", filterUrlize)
|
||||||
|
@ -105,9 +108,9 @@ func filterTruncatecharsHelper(s string, newLen int) string {
|
||||||
return string(runes)
|
return string(runes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func() bool, fn func(c rune, s int, idx int) int, finalize func()) {
|
func filterTruncateHTMLHelper(value string, newOutput *bytes.Buffer, cond func() bool, fn func(c rune, s int, idx int) int, finalize func()) {
|
||||||
vLen := len(value)
|
vLen := len(value)
|
||||||
tag_stack := make([]string, 0)
|
var tagStack []string
|
||||||
idx := 0
|
idx := 0
|
||||||
|
|
||||||
for idx < vLen && !cond() {
|
for idx < vLen && !cond() {
|
||||||
|
@ -118,17 +121,17 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
||||||
}
|
}
|
||||||
|
|
||||||
if c == '<' {
|
if c == '<' {
|
||||||
new_output.WriteRune(c)
|
newOutput.WriteRune(c)
|
||||||
idx += s // consume "<"
|
idx += s // consume "<"
|
||||||
|
|
||||||
if idx+1 < vLen {
|
if idx+1 < vLen {
|
||||||
if value[idx] == '/' {
|
if value[idx] == '/' {
|
||||||
// Close tag
|
// Close tag
|
||||||
|
|
||||||
new_output.WriteString("/")
|
newOutput.WriteString("/")
|
||||||
|
|
||||||
tag := ""
|
tag := ""
|
||||||
idx += 1 // consume "/"
|
idx++ // consume "/"
|
||||||
|
|
||||||
for idx < vLen {
|
for idx < vLen {
|
||||||
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
||||||
|
@ -146,21 +149,21 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
||||||
idx += size2
|
idx += size2
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tag_stack) > 0 {
|
if len(tagStack) > 0 {
|
||||||
// Ideally, the close tag is TOP of tag stack
|
// Ideally, the close tag is TOP of tag stack
|
||||||
// In malformed HTML, it must not be, so iterate through the stack and remove the tag
|
// In malformed HTML, it must not be, so iterate through the stack and remove the tag
|
||||||
for i := len(tag_stack) - 1; i >= 0; i-- {
|
for i := len(tagStack) - 1; i >= 0; i-- {
|
||||||
if tag_stack[i] == tag {
|
if tagStack[i] == tag {
|
||||||
// Found the tag
|
// Found the tag
|
||||||
tag_stack[i] = tag_stack[len(tag_stack)-1]
|
tagStack[i] = tagStack[len(tagStack)-1]
|
||||||
tag_stack = tag_stack[:len(tag_stack)-1]
|
tagStack = tagStack[:len(tagStack)-1]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new_output.WriteString(tag)
|
newOutput.WriteString(tag)
|
||||||
new_output.WriteString(">")
|
newOutput.WriteString(">")
|
||||||
} else {
|
} else {
|
||||||
// Open tag
|
// Open tag
|
||||||
|
|
||||||
|
@ -174,7 +177,7 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
new_output.WriteRune(c2)
|
newOutput.WriteRune(c2)
|
||||||
|
|
||||||
// End of tag found
|
// End of tag found
|
||||||
if c2 == '>' {
|
if c2 == '>' {
|
||||||
|
@ -194,7 +197,7 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add tag to stack
|
// Add tag to stack
|
||||||
tag_stack = append(tag_stack, tag)
|
tagStack = append(tagStack, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -204,10 +207,10 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
||||||
|
|
||||||
finalize()
|
finalize()
|
||||||
|
|
||||||
for i := len(tag_stack) - 1; i >= 0; i-- {
|
for i := len(tagStack) - 1; i >= 0; i-- {
|
||||||
tag := tag_stack[i]
|
tag := tagStack[i]
|
||||||
// Close everything from the regular tag stack
|
// Close everything from the regular tag stack
|
||||||
new_output.WriteString(fmt.Sprintf("</%s>", tag))
|
newOutput.WriteString(fmt.Sprintf("</%s>", tag))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,28 +220,28 @@ func filterTruncatechars(in *Value, param *Value) (*Value, *Error) {
|
||||||
return AsValue(filterTruncatecharsHelper(s, newLen)), nil
|
return AsValue(filterTruncatecharsHelper(s, newLen)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterTruncatecharsHtml(in *Value, param *Value) (*Value, *Error) {
|
func filterTruncatecharsHTML(in *Value, param *Value) (*Value, *Error) {
|
||||||
value := in.String()
|
value := in.String()
|
||||||
newLen := max(param.Integer()-3, 0)
|
newLen := max(param.Integer()-3, 0)
|
||||||
|
|
||||||
new_output := bytes.NewBuffer(nil)
|
newOutput := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
textcounter := 0
|
textcounter := 0
|
||||||
|
|
||||||
filterTruncateHtmlHelper(value, new_output, func() bool {
|
filterTruncateHTMLHelper(value, newOutput, func() bool {
|
||||||
return textcounter >= newLen
|
return textcounter >= newLen
|
||||||
}, func(c rune, s int, idx int) int {
|
}, func(c rune, s int, idx int) int {
|
||||||
textcounter++
|
textcounter++
|
||||||
new_output.WriteRune(c)
|
newOutput.WriteRune(c)
|
||||||
|
|
||||||
return idx + s
|
return idx + s
|
||||||
}, func() {
|
}, func() {
|
||||||
if textcounter >= newLen && textcounter < len(value) {
|
if textcounter >= newLen && textcounter < len(value) {
|
||||||
new_output.WriteString("...")
|
newOutput.WriteString("...")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return AsSafeValue(new_output.String()), nil
|
return AsSafeValue(newOutput.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterTruncatewords(in *Value, param *Value) (*Value, *Error) {
|
func filterTruncatewords(in *Value, param *Value) (*Value, *Error) {
|
||||||
|
@ -260,19 +263,19 @@ func filterTruncatewords(in *Value, param *Value) (*Value, *Error) {
|
||||||
return AsValue(strings.Join(out, " ")), nil
|
return AsValue(strings.Join(out, " ")), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterTruncatewordsHtml(in *Value, param *Value) (*Value, *Error) {
|
func filterTruncatewordsHTML(in *Value, param *Value) (*Value, *Error) {
|
||||||
value := in.String()
|
value := in.String()
|
||||||
newLen := max(param.Integer(), 0)
|
newLen := max(param.Integer(), 0)
|
||||||
|
|
||||||
new_output := bytes.NewBuffer(nil)
|
newOutput := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
wordcounter := 0
|
wordcounter := 0
|
||||||
|
|
||||||
filterTruncateHtmlHelper(value, new_output, func() bool {
|
filterTruncateHTMLHelper(value, newOutput, func() bool {
|
||||||
return wordcounter >= newLen
|
return wordcounter >= newLen
|
||||||
}, func(_ rune, _ int, idx int) int {
|
}, func(_ rune, _ int, idx int) int {
|
||||||
// Get next word
|
// Get next word
|
||||||
word_found := false
|
wordFound := false
|
||||||
|
|
||||||
for idx < len(value) {
|
for idx < len(value) {
|
||||||
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
||||||
|
@ -286,29 +289,29 @@ func filterTruncatewordsHtml(in *Value, param *Value) (*Value, *Error) {
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
|
|
||||||
new_output.WriteRune(c2)
|
newOutput.WriteRune(c2)
|
||||||
idx += size2
|
idx += size2
|
||||||
|
|
||||||
if c2 == ' ' || c2 == '.' || c2 == ',' || c2 == ';' {
|
if c2 == ' ' || c2 == '.' || c2 == ',' || c2 == ';' {
|
||||||
// Word ends here, stop capturing it now
|
// Word ends here, stop capturing it now
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
word_found = true
|
wordFound = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if word_found {
|
if wordFound {
|
||||||
wordcounter++
|
wordcounter++
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx
|
return idx
|
||||||
}, func() {
|
}, func() {
|
||||||
if wordcounter >= newLen {
|
if wordcounter >= newLen {
|
||||||
new_output.WriteString("...")
|
newOutput.WriteString("...")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return AsSafeValue(new_output.String()), nil
|
return AsSafeValue(newOutput.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterEscape(in *Value, param *Value) (*Value, *Error) {
|
func filterEscape(in *Value, param *Value) (*Value, *Error) {
|
||||||
|
@ -377,12 +380,11 @@ func filterAdd(in *Value, param *Value) (*Value, *Error) {
|
||||||
if in.IsNumber() && param.IsNumber() {
|
if in.IsNumber() && param.IsNumber() {
|
||||||
if in.IsFloat() || param.IsFloat() {
|
if in.IsFloat() || param.IsFloat() {
|
||||||
return AsValue(in.Float() + param.Float()), nil
|
return AsValue(in.Float() + param.Float()), nil
|
||||||
} else {
|
}
|
||||||
return AsValue(in.Integer() + param.Integer()), nil
|
return AsValue(in.Integer() + param.Integer()), nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// If in/param is not a number, we're relying on the
|
// If in/param is not a number, we're relying on the
|
||||||
// Value's String() convertion and just add them both together
|
// Value's String() conversion and just add them both together
|
||||||
return AsValue(in.String() + param.String()), nil
|
return AsValue(in.String() + param.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,11 +552,11 @@ func filterCenter(in *Value, param *Value) (*Value, *Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterDate(in *Value, param *Value) (*Value, *Error) {
|
func filterDate(in *Value, param *Value) (*Value, *Error) {
|
||||||
t, is_time := in.Interface().(time.Time)
|
t, isTime := in.Interface().(time.Time)
|
||||||
if !is_time {
|
if !isTime {
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Sender: "filter:date",
|
Sender: "filter:date",
|
||||||
ErrorMsg: "Filter input argument must be of type 'time.Time'.",
|
OrigError: errors.New("filter input argument must be of type 'time.Time'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AsValue(t.Format(param.String())), nil
|
return AsValue(t.Format(param.String())), nil
|
||||||
|
@ -612,6 +614,12 @@ func filterLinebreaks(in *Value, param *Value) (*Value, *Error) {
|
||||||
return AsValue(b.String()), nil
|
return AsValue(b.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func filterSplit(in *Value, param *Value) (*Value, *Error) {
|
||||||
|
chunks := strings.Split(in.String(), param.String())
|
||||||
|
|
||||||
|
return AsValue(chunks), nil
|
||||||
|
}
|
||||||
|
|
||||||
func filterLinebreaksbr(in *Value, param *Value) (*Value, *Error) {
|
func filterLinebreaksbr(in *Value, param *Value) (*Value, *Error) {
|
||||||
return AsValue(strings.Replace(in.String(), "\n", "<br />", -1)), nil
|
return AsValue(strings.Replace(in.String(), "\n", "<br />", -1)), nil
|
||||||
}
|
}
|
||||||
|
@ -641,7 +649,8 @@ func filterUrlencode(in *Value, param *Value) (*Value, *Error) {
|
||||||
var filterUrlizeURLRegexp = regexp.MustCompile(`((((http|https)://)|www\.|((^|[ ])[0-9A-Za-z_\-]+(\.com|\.net|\.org|\.info|\.biz|\.de))))(?U:.*)([ ]+|$)`)
|
var filterUrlizeURLRegexp = regexp.MustCompile(`((((http|https)://)|www\.|((^|[ ])[0-9A-Za-z_\-]+(\.com|\.net|\.org|\.info|\.biz|\.de))))(?U:.*)([ ]+|$)`)
|
||||||
var filterUrlizeEmailRegexp = regexp.MustCompile(`(\w+@\w+\.\w{2,4})`)
|
var filterUrlizeEmailRegexp = regexp.MustCompile(`(\w+@\w+\.\w{2,4})`)
|
||||||
|
|
||||||
func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
func filterUrlizeHelper(input string, autoescape bool, trunc int) (string, error) {
|
||||||
|
var soutErr error
|
||||||
sout := filterUrlizeURLRegexp.ReplaceAllStringFunc(input, func(raw_url string) string {
|
sout := filterUrlizeURLRegexp.ReplaceAllStringFunc(input, func(raw_url string) string {
|
||||||
var prefix string
|
var prefix string
|
||||||
var suffix string
|
var suffix string
|
||||||
|
@ -656,7 +665,8 @@ func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
||||||
|
|
||||||
t, err := ApplyFilter("iriencode", AsValue(raw_url), nil)
|
t, err := ApplyFilter("iriencode", AsValue(raw_url), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
soutErr = err
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
url := t.String()
|
url := t.String()
|
||||||
|
|
||||||
|
@ -673,16 +683,19 @@ func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
||||||
if autoescape {
|
if autoescape {
|
||||||
t, err := ApplyFilter("escape", AsValue(title), nil)
|
t, err := ApplyFilter("escape", AsValue(title), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
soutErr = err
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
title = t.String()
|
title = t.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf(`%s<a href="%s" rel="nofollow">%s</a>%s`, prefix, url, title, suffix)
|
return fmt.Sprintf(`%s<a href="%s" rel="nofollow">%s</a>%s`, prefix, url, title, suffix)
|
||||||
})
|
})
|
||||||
|
if soutErr != nil {
|
||||||
|
return "", soutErr
|
||||||
|
}
|
||||||
|
|
||||||
sout = filterUrlizeEmailRegexp.ReplaceAllStringFunc(sout, func(mail string) string {
|
sout = filterUrlizeEmailRegexp.ReplaceAllStringFunc(sout, func(mail string) string {
|
||||||
|
|
||||||
title := mail
|
title := mail
|
||||||
|
|
||||||
if trunc > 3 && len(title) > trunc {
|
if trunc > 3 && len(title) > trunc {
|
||||||
|
@ -692,7 +705,7 @@ func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
||||||
return fmt.Sprintf(`<a href="mailto:%s">%s</a>`, mail, title)
|
return fmt.Sprintf(`<a href="mailto:%s">%s</a>`, mail, title)
|
||||||
})
|
})
|
||||||
|
|
||||||
return sout
|
return sout, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterUrlize(in *Value, param *Value) (*Value, *Error) {
|
func filterUrlize(in *Value, param *Value) (*Value, *Error) {
|
||||||
|
@ -701,24 +714,36 @@ func filterUrlize(in *Value, param *Value) (*Value, *Error) {
|
||||||
autoescape = param.Bool()
|
autoescape = param.Bool()
|
||||||
}
|
}
|
||||||
|
|
||||||
return AsValue(filterUrlizeHelper(in.String(), autoescape, -1)), nil
|
s, err := filterUrlizeHelper(in.String(), autoescape, -1)
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return AsValue(s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterUrlizetrunc(in *Value, param *Value) (*Value, *Error) {
|
func filterUrlizetrunc(in *Value, param *Value) (*Value, *Error) {
|
||||||
return AsValue(filterUrlizeHelper(in.String(), true, param.Integer())), nil
|
s, err := filterUrlizeHelper(in.String(), true, param.Integer())
|
||||||
|
if err != nil {
|
||||||
|
return nil, &Error{
|
||||||
|
Sender: "filter:urlizetrunc",
|
||||||
|
OrigError: errors.New("you cannot pass more than 2 arguments to filter 'pluralize'"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AsValue(s), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterStringformat(in *Value, param *Value) (*Value, *Error) {
|
func filterStringformat(in *Value, param *Value) (*Value, *Error) {
|
||||||
return AsValue(fmt.Sprintf(param.String(), in.Interface())), nil
|
return AsValue(fmt.Sprintf(param.String(), in.Interface())), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var re_striptags = regexp.MustCompile("<[^>]*?>")
|
var reStriptags = regexp.MustCompile("<[^>]*?>")
|
||||||
|
|
||||||
func filterStriptags(in *Value, param *Value) (*Value, *Error) {
|
func filterStriptags(in *Value, param *Value) (*Value, *Error) {
|
||||||
s := in.String()
|
s := in.String()
|
||||||
|
|
||||||
// Strip all tags
|
// Strip all tags
|
||||||
s = re_striptags.ReplaceAllString(s, "")
|
s = reStriptags.ReplaceAllString(s, "")
|
||||||
|
|
||||||
return AsValue(strings.TrimSpace(s)), nil
|
return AsValue(strings.TrimSpace(s)), nil
|
||||||
}
|
}
|
||||||
|
@ -747,7 +772,7 @@ func filterPluralize(in *Value, param *Value) (*Value, *Error) {
|
||||||
if len(endings) > 2 {
|
if len(endings) > 2 {
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Sender: "filter:pluralize",
|
Sender: "filter:pluralize",
|
||||||
ErrorMsg: "You cannot pass more than 2 arguments to filter 'pluralize'.",
|
OrigError: errors.New("you cannot pass more than 2 arguments to filter 'pluralize'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(endings) == 1 {
|
if len(endings) == 1 {
|
||||||
|
@ -770,11 +795,10 @@ func filterPluralize(in *Value, param *Value) (*Value, *Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return AsValue(""), nil
|
return AsValue(""), nil
|
||||||
} else {
|
}
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Sender: "filter:pluralize",
|
Sender: "filter:pluralize",
|
||||||
ErrorMsg: "Filter 'pluralize' does only work on numbers.",
|
OrigError: errors.New("filter 'pluralize' does only work on numbers"),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +832,7 @@ func filterSlice(in *Value, param *Value) (*Value, *Error) {
|
||||||
if len(comp) != 2 {
|
if len(comp) != 2 {
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Sender: "filter:slice",
|
Sender: "filter:slice",
|
||||||
ErrorMsg: "Slice string must have the format 'from:to' [from/to can be omitted, but the ':' is required]",
|
OrigError: errors.New("Slice string must have the format 'from:to' [from/to can be omitted, but the ':' is required]"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,16 +868,16 @@ func filterWordcount(in *Value, param *Value) (*Value, *Error) {
|
||||||
|
|
||||||
func filterWordwrap(in *Value, param *Value) (*Value, *Error) {
|
func filterWordwrap(in *Value, param *Value) (*Value, *Error) {
|
||||||
words := strings.Fields(in.String())
|
words := strings.Fields(in.String())
|
||||||
words_len := len(words)
|
wordsLen := len(words)
|
||||||
wrap_at := param.Integer()
|
wrapAt := param.Integer()
|
||||||
if wrap_at <= 0 {
|
if wrapAt <= 0 {
|
||||||
return in, nil
|
return in, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
linecount := words_len/wrap_at + words_len%wrap_at
|
linecount := wordsLen/wrapAt + wordsLen%wrapAt
|
||||||
lines := make([]string, 0, linecount)
|
lines := make([]string, 0, linecount)
|
||||||
for i := 0; i < linecount; i++ {
|
for i := 0; i < linecount; i++ {
|
||||||
lines = append(lines, strings.Join(words[wrap_at*i:min(wrap_at*(i+1), words_len)], " "))
|
lines = append(lines, strings.Join(words[wrapAt*i:min(wrapAt*(i+1), wordsLen)], " "))
|
||||||
}
|
}
|
||||||
return AsValue(strings.Join(lines, "\n")), nil
|
return AsValue(strings.Join(lines, "\n")), nil
|
||||||
}
|
}
|
||||||
|
@ -864,27 +888,27 @@ func filterYesno(in *Value, param *Value) (*Value, *Error) {
|
||||||
1: "no",
|
1: "no",
|
||||||
2: "maybe",
|
2: "maybe",
|
||||||
}
|
}
|
||||||
param_string := param.String()
|
paramString := param.String()
|
||||||
custom_choices := strings.Split(param_string, ",")
|
customChoices := strings.Split(paramString, ",")
|
||||||
if len(param_string) > 0 {
|
if len(paramString) > 0 {
|
||||||
if len(custom_choices) > 3 {
|
if len(customChoices) > 3 {
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Sender: "filter:yesno",
|
Sender: "filter:yesno",
|
||||||
ErrorMsg: fmt.Sprintf("You cannot pass more than 3 options to the 'yesno'-filter (got: '%s').", param_string),
|
OrigError: errors.Errorf("You cannot pass more than 3 options to the 'yesno'-filter (got: '%s').", paramString),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(custom_choices) < 2 {
|
if len(customChoices) < 2 {
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Sender: "filter:yesno",
|
Sender: "filter:yesno",
|
||||||
ErrorMsg: fmt.Sprintf("You must pass either no or at least 2 arguments to the 'yesno'-filter (got: '%s').", param_string),
|
OrigError: errors.Errorf("You must pass either no or at least 2 arguments to the 'yesno'-filter (got: '%s').", paramString),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map to the options now
|
// Map to the options now
|
||||||
choices[0] = custom_choices[0]
|
choices[0] = customChoices[0]
|
||||||
choices[1] = custom_choices[1]
|
choices[1] = customChoices[1]
|
||||||
if len(custom_choices) == 3 {
|
if len(customChoices) == 3 {
|
||||||
choices[2] = custom_choices[2]
|
choices[2] = customChoices[2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
vendor/github.com/flosch/pongo2/lexer.go
generated
vendored
36
vendor/github.com/flosch/pongo2/lexer.go
generated
vendored
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -63,8 +65,8 @@ type lexer struct {
|
||||||
line int
|
line int
|
||||||
col int
|
col int
|
||||||
|
|
||||||
in_verbatim bool
|
inVerbatim bool
|
||||||
verbatim_name string
|
verbatimName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Token) String() string {
|
func (t *Token) String() string {
|
||||||
|
@ -115,7 +117,7 @@ func lex(name string, input string) ([]*Token, *Error) {
|
||||||
Line: errtoken.Line,
|
Line: errtoken.Line,
|
||||||
Column: errtoken.Col,
|
Column: errtoken.Col,
|
||||||
Sender: "lexer",
|
Sender: "lexer",
|
||||||
ErrorMsg: errtoken.Val,
|
OrigError: errors.New(errtoken.Val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return l.tokens, nil
|
return l.tokens, nil
|
||||||
|
@ -216,8 +218,8 @@ func (l *lexer) run() {
|
||||||
for {
|
for {
|
||||||
// TODO: Support verbatim tag names
|
// TODO: Support verbatim tag names
|
||||||
// https://docs.djangoproject.com/en/dev/ref/templates/builtins/#verbatim
|
// https://docs.djangoproject.com/en/dev/ref/templates/builtins/#verbatim
|
||||||
if l.in_verbatim {
|
if l.inVerbatim {
|
||||||
name := l.verbatim_name
|
name := l.verbatimName
|
||||||
if name != "" {
|
if name != "" {
|
||||||
name += " "
|
name += " "
|
||||||
}
|
}
|
||||||
|
@ -229,20 +231,20 @@ func (l *lexer) run() {
|
||||||
l.pos += w
|
l.pos += w
|
||||||
l.col += w
|
l.col += w
|
||||||
l.ignore()
|
l.ignore()
|
||||||
l.in_verbatim = false
|
l.inVerbatim = false
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(l.input[l.pos:], "{% verbatim %}") { // tag
|
} else if strings.HasPrefix(l.input[l.pos:], "{% verbatim %}") { // tag
|
||||||
if l.pos > l.start {
|
if l.pos > l.start {
|
||||||
l.emit(TokenHTML)
|
l.emit(TokenHTML)
|
||||||
}
|
}
|
||||||
l.in_verbatim = true
|
l.inVerbatim = true
|
||||||
w := len("{% verbatim %}")
|
w := len("{% verbatim %}")
|
||||||
l.pos += w
|
l.pos += w
|
||||||
l.col += w
|
l.col += w
|
||||||
l.ignore()
|
l.ignore()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !l.in_verbatim {
|
if !l.inVerbatim {
|
||||||
// Ignore single-line comments {# ... #}
|
// Ignore single-line comments {# ... #}
|
||||||
if strings.HasPrefix(l.input[l.pos:], "{#") {
|
if strings.HasPrefix(l.input[l.pos:], "{#") {
|
||||||
if l.pos > l.start {
|
if l.pos > l.start {
|
||||||
|
@ -303,7 +305,7 @@ func (l *lexer) run() {
|
||||||
l.emit(TokenHTML)
|
l.emit(TokenHTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.in_verbatim {
|
if l.inVerbatim {
|
||||||
l.errorf("verbatim-tag not closed, got EOF.")
|
l.errorf("verbatim-tag not closed, got EOF.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,7 +330,7 @@ outer_loop:
|
||||||
return l.stateIdentifier
|
return l.stateIdentifier
|
||||||
case l.accept(tokenDigits):
|
case l.accept(tokenDigits):
|
||||||
return l.stateNumber
|
return l.stateNumber
|
||||||
case l.accept(`"`):
|
case l.accept(`"'`):
|
||||||
return l.stateString
|
return l.stateString
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,10 +350,6 @@ outer_loop:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.pos < len(l.input) {
|
|
||||||
return l.errorf("Unknown character: %q (%d)", l.peek(), l.peek())
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +372,11 @@ func (l *lexer) stateIdentifier() lexerStateFn {
|
||||||
|
|
||||||
func (l *lexer) stateNumber() lexerStateFn {
|
func (l *lexer) stateNumber() lexerStateFn {
|
||||||
l.acceptRun(tokenDigits)
|
l.acceptRun(tokenDigits)
|
||||||
|
if l.accept(tokenIdentifierCharsWithDigits) {
|
||||||
|
// This seems to be an identifier starting with a number.
|
||||||
|
// See https://github.com/flosch/pongo2/issues/151
|
||||||
|
return l.stateIdentifier()
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Maybe context-sensitive number lexing?
|
Maybe context-sensitive number lexing?
|
||||||
* comments.0.Text // first comment
|
* comments.0.Text // first comment
|
||||||
|
@ -393,9 +396,10 @@ func (l *lexer) stateNumber() lexerStateFn {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *lexer) stateString() lexerStateFn {
|
func (l *lexer) stateString() lexerStateFn {
|
||||||
|
quotationMark := l.value()
|
||||||
l.ignore()
|
l.ignore()
|
||||||
l.startcol -= 1 // we're starting the position at the first "
|
l.startcol-- // we're starting the position at the first "
|
||||||
for !l.accept(`"`) {
|
for !l.accept(quotationMark) {
|
||||||
switch l.next() {
|
switch l.next() {
|
||||||
case '\\':
|
case '\\':
|
||||||
// escape sequence
|
// escape sequence
|
||||||
|
|
8
vendor/github.com/flosch/pongo2/nodes.go
generated
vendored
8
vendor/github.com/flosch/pongo2/nodes.go
generated
vendored
|
@ -1,17 +1,13 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
// The root document
|
// The root document
|
||||||
type nodeDocument struct {
|
type nodeDocument struct {
|
||||||
Nodes []INode
|
Nodes []INode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (doc *nodeDocument) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (doc *nodeDocument) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
for _, n := range doc.Nodes {
|
for _, n := range doc.Nodes {
|
||||||
err := n.Execute(ctx, buffer)
|
err := n.Execute(ctx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
8
vendor/github.com/flosch/pongo2/nodes_html.go
generated
vendored
8
vendor/github.com/flosch/pongo2/nodes_html.go
generated
vendored
|
@ -1,14 +1,10 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type nodeHTML struct {
|
type nodeHTML struct {
|
||||||
token *Token
|
token *Token
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nodeHTML) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (n *nodeHTML) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
buffer.WriteString(n.token.Val)
|
writer.WriteString(n.token.Val)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
8
vendor/github.com/flosch/pongo2/nodes_wrapper.go
generated
vendored
8
vendor/github.com/flosch/pongo2/nodes_wrapper.go
generated
vendored
|
@ -1,17 +1,13 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NodeWrapper struct {
|
type NodeWrapper struct {
|
||||||
Endtag string
|
Endtag string
|
||||||
nodes []INode
|
nodes []INode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wrapper *NodeWrapper) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (wrapper *NodeWrapper) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
for _, n := range wrapper.nodes {
|
for _, n := range wrapper.nodes {
|
||||||
err := n.Execute(ctx, buffer)
|
err := n.Execute(ctx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
72
vendor/github.com/flosch/pongo2/parser.go
generated
vendored
72
vendor/github.com/flosch/pongo2/parser.go
generated
vendored
|
@ -1,13 +1,14 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type INode interface {
|
type INode interface {
|
||||||
Execute(*ExecutionContext, *bytes.Buffer) *Error
|
Execute(*ExecutionContext, TemplateWriter) *Error
|
||||||
}
|
}
|
||||||
|
|
||||||
type IEvaluator interface {
|
type IEvaluator interface {
|
||||||
|
@ -30,7 +31,7 @@ type Parser struct {
|
||||||
name string
|
name string
|
||||||
idx int
|
idx int
|
||||||
tokens []*Token
|
tokens []*Token
|
||||||
last_token *Token
|
lastToken *Token
|
||||||
|
|
||||||
// if the parser parses a template document, here will be
|
// if the parser parses a template document, here will be
|
||||||
// a reference to it (needed to access the template through Tags)
|
// a reference to it (needed to access the template through Tags)
|
||||||
|
@ -47,7 +48,7 @@ func newParser(name string, tokens []*Token, template *Template) *Parser {
|
||||||
template: template,
|
template: template,
|
||||||
}
|
}
|
||||||
if len(tokens) > 0 {
|
if len(tokens) > 0 {
|
||||||
p.last_token = tokens[len(tokens)-1]
|
p.lastToken = tokens[len(tokens)-1]
|
||||||
}
|
}
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
@ -175,7 +176,7 @@ func (p *Parser) GetR(shift int) *Token {
|
||||||
return p.Get(i)
|
return p.Get(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produces a nice error message and returns an error-object.
|
// Error produces a nice error message and returns an error-object.
|
||||||
// The 'token'-argument is optional. If provided, it will take
|
// The 'token'-argument is optional. If provided, it will take
|
||||||
// the token's position information. If not provided, it will
|
// the token's position information. If not provided, it will
|
||||||
// automatically use the CURRENT token's position information.
|
// automatically use the CURRENT token's position information.
|
||||||
|
@ -202,7 +203,7 @@ func (p *Parser) Error(msg string, token *Token) *Error {
|
||||||
Line: line,
|
Line: line,
|
||||||
Column: col,
|
Column: col,
|
||||||
Token: token,
|
Token: token,
|
||||||
ErrorMsg: msg,
|
OrigError: errors.New(msg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,19 +213,19 @@ func (p *Parser) Error(msg string, token *Token) *Error {
|
||||||
func (p *Parser) WrapUntilTag(names ...string) (*NodeWrapper, *Parser, *Error) {
|
func (p *Parser) WrapUntilTag(names ...string) (*NodeWrapper, *Parser, *Error) {
|
||||||
wrapper := &NodeWrapper{}
|
wrapper := &NodeWrapper{}
|
||||||
|
|
||||||
tagArgs := make([]*Token, 0)
|
var tagArgs []*Token
|
||||||
|
|
||||||
for p.Remaining() > 0 {
|
for p.Remaining() > 0 {
|
||||||
// New tag, check whether we have to stop wrapping here
|
// New tag, check whether we have to stop wrapping here
|
||||||
if p.Peek(TokenSymbol, "{%") != nil {
|
if p.Peek(TokenSymbol, "{%") != nil {
|
||||||
tag_ident := p.PeekTypeN(1, TokenIdentifier)
|
tagIdent := p.PeekTypeN(1, TokenIdentifier)
|
||||||
|
|
||||||
if tag_ident != nil {
|
if tagIdent != nil {
|
||||||
// We've found a (!) end-tag
|
// We've found a (!) end-tag
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
for _, n := range names {
|
for _, n := range names {
|
||||||
if tag_ident.Val == n {
|
if tagIdent.Val == n {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -238,19 +239,18 @@ func (p *Parser) WrapUntilTag(names ...string) (*NodeWrapper, *Parser, *Error) {
|
||||||
for {
|
for {
|
||||||
if p.Match(TokenSymbol, "%}") != nil {
|
if p.Match(TokenSymbol, "%}") != nil {
|
||||||
// Okay, end the wrapping here
|
// Okay, end the wrapping here
|
||||||
wrapper.Endtag = tag_ident.Val
|
wrapper.Endtag = tagIdent.Val
|
||||||
return wrapper, newParser(p.template.name, tagArgs, p.template), nil
|
return wrapper, newParser(p.template.name, tagArgs, p.template), nil
|
||||||
} else {
|
}
|
||||||
t := p.Current()
|
t := p.Current()
|
||||||
p.Consume()
|
p.Consume()
|
||||||
if t == nil {
|
if t == nil {
|
||||||
return nil, nil, p.Error("Unexpected EOF.", p.last_token)
|
return nil, nil, p.Error("Unexpected EOF.", p.lastToken)
|
||||||
}
|
}
|
||||||
tagArgs = append(tagArgs, t)
|
tagArgs = append(tagArgs, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,5 +263,47 @@ func (p *Parser) WrapUntilTag(names ...string) (*NodeWrapper, *Parser, *Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")),
|
return nil, nil, p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")),
|
||||||
p.last_token)
|
p.lastToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skips all nodes between starting tag and "{% endtag %}"
|
||||||
|
func (p *Parser) SkipUntilTag(names ...string) *Error {
|
||||||
|
for p.Remaining() > 0 {
|
||||||
|
// New tag, check whether we have to stop wrapping here
|
||||||
|
if p.Peek(TokenSymbol, "{%") != nil {
|
||||||
|
tagIdent := p.PeekTypeN(1, TokenIdentifier)
|
||||||
|
|
||||||
|
if tagIdent != nil {
|
||||||
|
// We've found a (!) end-tag
|
||||||
|
|
||||||
|
found := false
|
||||||
|
for _, n := range names {
|
||||||
|
if tagIdent.Val == n {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only process the tag if we've found an end tag
|
||||||
|
if found {
|
||||||
|
// Okay, endtag found.
|
||||||
|
p.ConsumeN(2) // '{%' tagname
|
||||||
|
|
||||||
|
for {
|
||||||
|
if p.Match(TokenSymbol, "%}") != nil {
|
||||||
|
// Done skipping, exit.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t := p.Current()
|
||||||
|
p.Consume()
|
||||||
|
if t == nil {
|
||||||
|
return p.Error("Unexpected EOF.", p.lastToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.Error(fmt.Sprintf("Unexpected EOF, expected tag %s.", strings.Join(names, " or ")), p.lastToken)
|
||||||
}
|
}
|
||||||
|
|
134
vendor/github.com/flosch/pongo2/parser_expression.go
generated
vendored
134
vendor/github.com/flosch/pongo2/parser_expression.go
generated
vendored
|
@ -1,7 +1,6 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
@ -10,29 +9,29 @@ type Expression struct {
|
||||||
// TODO: Add location token?
|
// TODO: Add location token?
|
||||||
expr1 IEvaluator
|
expr1 IEvaluator
|
||||||
expr2 IEvaluator
|
expr2 IEvaluator
|
||||||
op_token *Token
|
opToken *Token
|
||||||
}
|
}
|
||||||
|
|
||||||
type relationalExpression struct {
|
type relationalExpression struct {
|
||||||
// TODO: Add location token?
|
// TODO: Add location token?
|
||||||
expr1 IEvaluator
|
expr1 IEvaluator
|
||||||
expr2 IEvaluator
|
expr2 IEvaluator
|
||||||
op_token *Token
|
opToken *Token
|
||||||
}
|
}
|
||||||
|
|
||||||
type simpleExpression struct {
|
type simpleExpression struct {
|
||||||
negate bool
|
negate bool
|
||||||
negative_sign bool
|
negativeSign bool
|
||||||
term1 IEvaluator
|
term1 IEvaluator
|
||||||
term2 IEvaluator
|
term2 IEvaluator
|
||||||
op_token *Token
|
opToken *Token
|
||||||
}
|
}
|
||||||
|
|
||||||
type term struct {
|
type term struct {
|
||||||
// TODO: Add location token?
|
// TODO: Add location token?
|
||||||
factor1 IEvaluator
|
factor1 IEvaluator
|
||||||
factor2 IEvaluator
|
factor2 IEvaluator
|
||||||
op_token *Token
|
opToken *Token
|
||||||
}
|
}
|
||||||
|
|
||||||
type power struct {
|
type power struct {
|
||||||
|
@ -56,14 +55,14 @@ func (expr *simpleExpression) FilterApplied(name string) bool {
|
||||||
(expr.term2 != nil && expr.term2.FilterApplied(name)))
|
(expr.term2 != nil && expr.term2.FilterApplied(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *term) FilterApplied(name string) bool {
|
func (expr *term) FilterApplied(name string) bool {
|
||||||
return t.factor1.FilterApplied(name) && (t.factor2 == nil ||
|
return expr.factor1.FilterApplied(name) && (expr.factor2 == nil ||
|
||||||
(t.factor2 != nil && t.factor2.FilterApplied(name)))
|
(expr.factor2 != nil && expr.factor2.FilterApplied(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *power) FilterApplied(name string) bool {
|
func (expr *power) FilterApplied(name string) bool {
|
||||||
return p.power1.FilterApplied(name) && (p.power2 == nil ||
|
return expr.power1.FilterApplied(name) && (expr.power2 == nil ||
|
||||||
(p.power2 != nil && p.power2.FilterApplied(name)))
|
(expr.power2 != nil && expr.power2.FilterApplied(name)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *Expression) GetPositionToken() *Token {
|
func (expr *Expression) GetPositionToken() *Token {
|
||||||
|
@ -86,48 +85,48 @@ func (expr *power) GetPositionToken() *Token {
|
||||||
return expr.power1.GetPositionToken()
|
return expr.power1.GetPositionToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *Expression) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (expr *Expression) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := expr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *relationalExpression) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (expr *relationalExpression) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := expr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *simpleExpression) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (expr *simpleExpression) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := expr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *term) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (expr *term) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := expr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *power) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (expr *power) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := expr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,13 +140,13 @@ func (expr *Expression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch expr.op_token.Val {
|
switch expr.opToken.Val {
|
||||||
case "and", "&&":
|
case "and", "&&":
|
||||||
return AsValue(v1.IsTrue() && v2.IsTrue()), nil
|
return AsValue(v1.IsTrue() && v2.IsTrue()), nil
|
||||||
case "or", "||":
|
case "or", "||":
|
||||||
return AsValue(v1.IsTrue() || v2.IsTrue()), nil
|
return AsValue(v1.IsTrue() || v2.IsTrue()), nil
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unimplemented: %s", expr.op_token.Val))
|
return nil, ctx.Error(fmt.Sprintf("unimplemented: %s", expr.opToken.Val), expr.opToken)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return v1, nil
|
return v1, nil
|
||||||
|
@ -164,39 +163,35 @@ func (expr *relationalExpression) Evaluate(ctx *ExecutionContext) (*Value, *Erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch expr.op_token.Val {
|
switch expr.opToken.Val {
|
||||||
case "<=":
|
case "<=":
|
||||||
if v1.IsFloat() || v2.IsFloat() {
|
if v1.IsFloat() || v2.IsFloat() {
|
||||||
return AsValue(v1.Float() <= v2.Float()), nil
|
return AsValue(v1.Float() <= v2.Float()), nil
|
||||||
} else {
|
|
||||||
return AsValue(v1.Integer() <= v2.Integer()), nil
|
|
||||||
}
|
}
|
||||||
|
return AsValue(v1.Integer() <= v2.Integer()), nil
|
||||||
case ">=":
|
case ">=":
|
||||||
if v1.IsFloat() || v2.IsFloat() {
|
if v1.IsFloat() || v2.IsFloat() {
|
||||||
return AsValue(v1.Float() >= v2.Float()), nil
|
return AsValue(v1.Float() >= v2.Float()), nil
|
||||||
} else {
|
|
||||||
return AsValue(v1.Integer() >= v2.Integer()), nil
|
|
||||||
}
|
}
|
||||||
|
return AsValue(v1.Integer() >= v2.Integer()), nil
|
||||||
case "==":
|
case "==":
|
||||||
return AsValue(v1.EqualValueTo(v2)), nil
|
return AsValue(v1.EqualValueTo(v2)), nil
|
||||||
case ">":
|
case ">":
|
||||||
if v1.IsFloat() || v2.IsFloat() {
|
if v1.IsFloat() || v2.IsFloat() {
|
||||||
return AsValue(v1.Float() > v2.Float()), nil
|
return AsValue(v1.Float() > v2.Float()), nil
|
||||||
} else {
|
|
||||||
return AsValue(v1.Integer() > v2.Integer()), nil
|
|
||||||
}
|
}
|
||||||
|
return AsValue(v1.Integer() > v2.Integer()), nil
|
||||||
case "<":
|
case "<":
|
||||||
if v1.IsFloat() || v2.IsFloat() {
|
if v1.IsFloat() || v2.IsFloat() {
|
||||||
return AsValue(v1.Float() < v2.Float()), nil
|
return AsValue(v1.Float() < v2.Float()), nil
|
||||||
} else {
|
|
||||||
return AsValue(v1.Integer() < v2.Integer()), nil
|
|
||||||
}
|
}
|
||||||
|
return AsValue(v1.Integer() < v2.Integer()), nil
|
||||||
case "!=", "<>":
|
case "!=", "<>":
|
||||||
return AsValue(!v1.EqualValueTo(v2)), nil
|
return AsValue(!v1.EqualValueTo(v2)), nil
|
||||||
case "in":
|
case "in":
|
||||||
return AsValue(v2.Contains(v1)), nil
|
return AsValue(v2.Contains(v1)), nil
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unimplemented: %s", expr.op_token.Val))
|
return nil, ctx.Error(fmt.Sprintf("unimplemented: %s", expr.opToken.Val), expr.opToken)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return v1, nil
|
return v1, nil
|
||||||
|
@ -214,7 +209,7 @@ func (expr *simpleExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
result = result.Negate()
|
result = result.Negate()
|
||||||
}
|
}
|
||||||
|
|
||||||
if expr.negative_sign {
|
if expr.negativeSign {
|
||||||
if result.IsNumber() {
|
if result.IsNumber() {
|
||||||
switch {
|
switch {
|
||||||
case result.IsFloat():
|
case result.IsFloat():
|
||||||
|
@ -222,7 +217,7 @@ func (expr *simpleExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
case result.IsInteger():
|
case result.IsInteger():
|
||||||
result = AsValue(-1 * result.Integer())
|
result = AsValue(-1 * result.Integer())
|
||||||
default:
|
default:
|
||||||
panic("not possible")
|
return nil, ctx.Error("Operation between a number and a non-(float/integer) is not possible", nil)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, ctx.Error("Negative sign on a non-number expression", expr.GetPositionToken())
|
return nil, ctx.Error("Negative sign on a non-number expression", expr.GetPositionToken())
|
||||||
|
@ -234,42 +229,40 @@ func (expr *simpleExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch expr.op_token.Val {
|
switch expr.opToken.Val {
|
||||||
case "+":
|
case "+":
|
||||||
if result.IsFloat() || t2.IsFloat() {
|
if result.IsFloat() || t2.IsFloat() {
|
||||||
// Result will be a float
|
// Result will be a float
|
||||||
return AsValue(result.Float() + t2.Float()), nil
|
return AsValue(result.Float() + t2.Float()), nil
|
||||||
} else {
|
}
|
||||||
// Result will be an integer
|
// Result will be an integer
|
||||||
return AsValue(result.Integer() + t2.Integer()), nil
|
return AsValue(result.Integer() + t2.Integer()), nil
|
||||||
}
|
|
||||||
case "-":
|
case "-":
|
||||||
if result.IsFloat() || t2.IsFloat() {
|
if result.IsFloat() || t2.IsFloat() {
|
||||||
// Result will be a float
|
// Result will be a float
|
||||||
return AsValue(result.Float() - t2.Float()), nil
|
return AsValue(result.Float() - t2.Float()), nil
|
||||||
} else {
|
}
|
||||||
// Result will be an integer
|
// Result will be an integer
|
||||||
return AsValue(result.Integer() - t2.Integer()), nil
|
return AsValue(result.Integer() - t2.Integer()), nil
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
panic("unimplemented")
|
return nil, ctx.Error("Unimplemented", expr.GetPositionToken())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
func (expr *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
f1, err := t.factor1.Evaluate(ctx)
|
f1, err := expr.factor1.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if t.factor2 != nil {
|
if expr.factor2 != nil {
|
||||||
f2, err := t.factor2.Evaluate(ctx)
|
f2, err := expr.factor2.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
switch t.op_token.Val {
|
switch expr.opToken.Val {
|
||||||
case "*":
|
case "*":
|
||||||
if f1.IsFloat() || f2.IsFloat() {
|
if f1.IsFloat() || f2.IsFloat() {
|
||||||
// Result will be float
|
// Result will be float
|
||||||
|
@ -288,27 +281,26 @@ func (t *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
// Result will be int
|
// Result will be int
|
||||||
return AsValue(f1.Integer() % f2.Integer()), nil
|
return AsValue(f1.Integer() % f2.Integer()), nil
|
||||||
default:
|
default:
|
||||||
panic("unimplemented")
|
return nil, ctx.Error("unimplemented", expr.opToken)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return f1, nil
|
return f1, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *power) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
func (expr *power) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
p1, err := pw.power1.Evaluate(ctx)
|
p1, err := expr.power1.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if pw.power2 != nil {
|
if expr.power2 != nil {
|
||||||
p2, err := pw.power2.Evaluate(ctx)
|
p2, err := expr.power2.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return AsValue(math.Pow(p1.Float(), p2.Float())), nil
|
return AsValue(math.Pow(p1.Float(), p2.Float())), nil
|
||||||
} else {
|
|
||||||
return p1, nil
|
|
||||||
}
|
}
|
||||||
|
return p1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseFactor() (IEvaluator, *Error) {
|
func (p *Parser) parseFactor() (IEvaluator, *Error) {
|
||||||
|
@ -352,19 +344,19 @@ func (p *Parser) parsePower() (IEvaluator, *Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseTerm() (IEvaluator, *Error) {
|
func (p *Parser) parseTerm() (IEvaluator, *Error) {
|
||||||
return_term := new(term)
|
returnTerm := new(term)
|
||||||
|
|
||||||
factor1, err := p.parsePower()
|
factor1, err := p.parsePower()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return_term.factor1 = factor1
|
returnTerm.factor1 = factor1
|
||||||
|
|
||||||
for p.PeekOne(TokenSymbol, "*", "/", "%") != nil {
|
for p.PeekOne(TokenSymbol, "*", "/", "%") != nil {
|
||||||
if return_term.op_token != nil {
|
if returnTerm.opToken != nil {
|
||||||
// Create new sub-term
|
// Create new sub-term
|
||||||
return_term = &term{
|
returnTerm = &term{
|
||||||
factor1: return_term,
|
factor1: returnTerm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,16 +368,16 @@ func (p *Parser) parseTerm() (IEvaluator, *Error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return_term.op_token = op
|
returnTerm.opToken = op
|
||||||
return_term.factor2 = factor2
|
returnTerm.factor2 = factor2
|
||||||
}
|
}
|
||||||
|
|
||||||
if return_term.op_token == nil {
|
if returnTerm.opToken == nil {
|
||||||
// Shortcut for faster evaluation
|
// Shortcut for faster evaluation
|
||||||
return return_term.factor1, nil
|
return returnTerm.factor1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return return_term, nil
|
return returnTerm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
||||||
|
@ -393,7 +385,7 @@ func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
||||||
|
|
||||||
if sign := p.MatchOne(TokenSymbol, "+", "-"); sign != nil {
|
if sign := p.MatchOne(TokenSymbol, "+", "-"); sign != nil {
|
||||||
if sign.Val == "-" {
|
if sign.Val == "-" {
|
||||||
expr.negative_sign = true
|
expr.negativeSign = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,7 +400,7 @@ func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
||||||
expr.term1 = term1
|
expr.term1 = term1
|
||||||
|
|
||||||
for p.PeekOne(TokenSymbol, "+", "-") != nil {
|
for p.PeekOne(TokenSymbol, "+", "-") != nil {
|
||||||
if expr.op_token != nil {
|
if expr.opToken != nil {
|
||||||
// New sub expr
|
// New sub expr
|
||||||
expr = &simpleExpression{
|
expr = &simpleExpression{
|
||||||
term1: expr,
|
term1: expr,
|
||||||
|
@ -424,10 +416,10 @@ func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expr.term2 = term2
|
expr.term2 = term2
|
||||||
expr.op_token = op
|
expr.opToken = op
|
||||||
}
|
}
|
||||||
|
|
||||||
if expr.negate == false && expr.negative_sign == false && expr.term2 == nil {
|
if expr.negate == false && expr.negativeSign == false && expr.term2 == nil {
|
||||||
// Shortcut for faster evaluation
|
// Shortcut for faster evaluation
|
||||||
return expr.term1, nil
|
return expr.term1, nil
|
||||||
}
|
}
|
||||||
|
@ -450,14 +442,14 @@ func (p *Parser) parseRelationalExpression() (IEvaluator, *Error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
expr.op_token = t
|
expr.opToken = t
|
||||||
expr.expr2 = expr2
|
expr.expr2 = expr2
|
||||||
} else if t := p.MatchOne(TokenKeyword, "in"); t != nil {
|
} else if t := p.MatchOne(TokenKeyword, "in"); t != nil {
|
||||||
expr2, err := p.parseSimpleExpression()
|
expr2, err := p.parseSimpleExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
expr.op_token = t
|
expr.opToken = t
|
||||||
expr.expr2 = expr2
|
expr.expr2 = expr2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +479,7 @@ func (p *Parser) ParseExpression() (IEvaluator, *Error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
exp.expr2 = expr2
|
exp.expr2 = expr2
|
||||||
exp.op_token = op
|
exp.opToken = op
|
||||||
}
|
}
|
||||||
|
|
||||||
if exp.expr2 == nil {
|
if exp.expr2 == nil {
|
||||||
|
|
6
vendor/github.com/flosch/pongo2/pongo2.go
generated
vendored
6
vendor/github.com/flosch/pongo2/pongo2.go
generated
vendored
|
@ -1,10 +1,10 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
// Version string
|
// Version string
|
||||||
const Version = "v3"
|
const Version = "dev"
|
||||||
|
|
||||||
// Helper function which panics, if a Template couldn't
|
// Must panics, if a Template couldn't successfully parsed. This is how you
|
||||||
// successfully parsed. This is how you would use it:
|
// would use it:
|
||||||
// var baseTemplate = pongo2.Must(pongo2.FromFile("templates/base.html"))
|
// var baseTemplate = pongo2.Must(pongo2.FromFile("templates/base.html"))
|
||||||
func Must(tpl *Template, err error) *Template {
|
func Must(tpl *Template, err error) *Template {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
31
vendor/github.com/flosch/pongo2/pongo2_issues_test.go
generated
vendored
31
vendor/github.com/flosch/pongo2/pongo2_issues_test.go
generated
vendored
|
@ -1,20 +1,29 @@
|
||||||
package pongo2
|
package pongo2_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "gopkg.in/check.v1"
|
"github.com/flosch/pongo2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Hook up gocheck into the "go test" runner.
|
func TestIssue151(t *testing.T) {
|
||||||
|
tpl, err := pongo2.FromString("{{ mydict.51232_3 }}{{ 12345_123}}{{ 995189baz }}")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestIssues(t *testing.T) { TestingT(t) }
|
str, err := tpl.Execute(pongo2.Context{
|
||||||
|
"mydict": map[string]string{
|
||||||
|
"51232_3": "foo",
|
||||||
|
},
|
||||||
|
"12345_123": "bar",
|
||||||
|
"995189baz": "baz",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
type IssueTestSuite struct{}
|
if str != "foobarbaz" {
|
||||||
|
t.Fatalf("Expected output 'foobarbaz', but got '%s'.", str)
|
||||||
var _ = Suite(&IssueTestSuite{})
|
}
|
||||||
|
|
||||||
func (s *TestSuite) TestIssues(c *C) {
|
|
||||||
// Add a test for any issue
|
|
||||||
c.Check(42, Equals, 42)
|
|
||||||
}
|
}
|
||||||
|
|
187
vendor/github.com/flosch/pongo2/pongo2_template_test.go
generated
vendored
187
vendor/github.com/flosch/pongo2/pongo2_template_test.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
package pongo2
|
package pongo2_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -9,9 +9,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/flosch/pongo2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var admin_list = []string{"user2"}
|
var adminList = []string{"user2"}
|
||||||
|
|
||||||
var time1 = time.Date(2014, 06, 10, 15, 30, 15, 0, time.UTC)
|
var time1 = time.Date(2014, 06, 10, 15, 30, 15, 0, time.UTC)
|
||||||
var time2 = time.Date(2011, 03, 21, 8, 37, 56, 12, time.UTC)
|
var time2 = time.Date(2011, 03, 21, 8, 37, 56, 12, time.UTC)
|
||||||
|
@ -32,8 +34,8 @@ type comment struct {
|
||||||
Text string
|
Text string
|
||||||
}
|
}
|
||||||
|
|
||||||
func is_admin(u *user) bool {
|
func isAdmin(u *user) bool {
|
||||||
for _, a := range admin_list {
|
for _, a := range adminList {
|
||||||
if a == u.Name {
|
if a == u.Name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -41,12 +43,12 @@ func is_admin(u *user) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *user) Is_admin() *Value {
|
func (u *user) Is_admin() *pongo2.Value {
|
||||||
return AsValue(is_admin(u))
|
return pongo2.AsValue(isAdmin(u))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *user) Is_admin2() bool {
|
func (u *user) Is_admin2() bool {
|
||||||
return is_admin(u)
|
return isAdmin(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *post) String() string {
|
func (p *post) String() string {
|
||||||
|
@ -60,70 +62,49 @@ func (p *post) String() string {
|
||||||
type tagSandboxDemoTag struct {
|
type tagSandboxDemoTag struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagSandboxDemoTag) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagSandboxDemoTag) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) *pongo2.Error {
|
||||||
buffer.WriteString("hello")
|
writer.WriteString("hello")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagSandboxDemoTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagSandboxDemoTagParser(doc *pongo2.Parser, start *pongo2.Token, arguments *pongo2.Parser) (pongo2.INodeTag, *pongo2.Error) {
|
||||||
return &tagSandboxDemoTag{}, nil
|
return &tagSandboxDemoTag{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func BannedFilterFn(in *Value, params *Value) (*Value, *Error) {
|
func BannedFilterFn(in *pongo2.Value, params *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
|
||||||
return in, nil
|
return in, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
DefaultSet.Debug = true
|
pongo2.DefaultSet.Debug = true
|
||||||
|
|
||||||
RegisterFilter("banned_filter", BannedFilterFn)
|
pongo2.RegisterFilter("banned_filter", BannedFilterFn)
|
||||||
RegisterFilter("unbanned_filter", BannedFilterFn)
|
pongo2.RegisterFilter("unbanned_filter", BannedFilterFn)
|
||||||
RegisterTag("banned_tag", tagSandboxDemoTagParser)
|
pongo2.RegisterTag("banned_tag", tagSandboxDemoTagParser)
|
||||||
RegisterTag("unbanned_tag", tagSandboxDemoTagParser)
|
pongo2.RegisterTag("unbanned_tag", tagSandboxDemoTagParser)
|
||||||
|
|
||||||
DefaultSet.BanFilter("banned_filter")
|
pongo2.DefaultSet.BanFilter("banned_filter")
|
||||||
DefaultSet.BanTag("banned_tag")
|
pongo2.DefaultSet.BanTag("banned_tag")
|
||||||
|
|
||||||
// Allow different kind of levels inside template_tests/
|
|
||||||
abs_path, err := filepath.Abs("./template_tests/*")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
DefaultSet.SandboxDirectories = append(DefaultSet.SandboxDirectories, abs_path)
|
|
||||||
|
|
||||||
abs_path, err = filepath.Abs("./template_tests/*/*")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
DefaultSet.SandboxDirectories = append(DefaultSet.SandboxDirectories, abs_path)
|
|
||||||
|
|
||||||
abs_path, err = filepath.Abs("./template_tests/*/*/*")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
DefaultSet.SandboxDirectories = append(DefaultSet.SandboxDirectories, abs_path)
|
|
||||||
|
|
||||||
// Allow pongo2 temp files
|
|
||||||
DefaultSet.SandboxDirectories = append(DefaultSet.SandboxDirectories, "/tmp/pongo2_*")
|
|
||||||
|
|
||||||
f, err := ioutil.TempFile("/tmp/", "pongo2_")
|
f, err := ioutil.TempFile("/tmp/", "pongo2_")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("cannot write to /tmp/")
|
panic("cannot write to /tmp/")
|
||||||
}
|
}
|
||||||
f.Write([]byte("Hello from pongo2"))
|
f.Write([]byte("Hello from pongo2"))
|
||||||
DefaultSet.Globals["temp_file"] = f.Name()
|
pongo2.DefaultSet.Globals["temp_file"] = f.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End setup sandbox
|
* End setup sandbox
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var tplContext = Context{
|
var tplContext = pongo2.Context{
|
||||||
"number": 11,
|
"number": 11,
|
||||||
"simple": map[string]interface{}{
|
"simple": map[string]interface{}{
|
||||||
"number": 42,
|
"number": 42,
|
||||||
"name": "john doe",
|
"name": "john doe",
|
||||||
"included_file": "INCLUDES.helper",
|
"included_file": "INCLUDES.helper",
|
||||||
|
"included_file_not_exists": "INCLUDES.helper.not_exists",
|
||||||
"nil": nil,
|
"nil": nil,
|
||||||
"uint": uint(8),
|
"uint": uint(8),
|
||||||
"float": float64(3.1415),
|
"float": float64(3.1415),
|
||||||
|
@ -142,13 +123,23 @@ Yep!`,
|
||||||
"escape_js_test": `escape sequences \r\n\'\" special chars "?!=$<>`,
|
"escape_js_test": `escape sequences \r\n\'\" special chars "?!=$<>`,
|
||||||
"one_item_list": []int{99},
|
"one_item_list": []int{99},
|
||||||
"multiple_item_list": []int{1, 1, 2, 3, 5, 8, 13, 21, 34, 55},
|
"multiple_item_list": []int{1, 1, 2, 3, 5, 8, 13, 21, 34, 55},
|
||||||
|
"unsorted_int_list": []int{192, 581, 22, 1, 249, 9999, 1828591, 8271},
|
||||||
|
"fixed_item_list": [...]int{1, 2, 3, 4},
|
||||||
"misc_list": []interface{}{"Hello", 99, 3.14, "good"},
|
"misc_list": []interface{}{"Hello", 99, 3.14, "good"},
|
||||||
"escape_text": "This is \\a Test. \"Yep\". 'Yep'.",
|
"escape_text": "This is \\a Test. \"Yep\". 'Yep'.",
|
||||||
"xss": "<script>alert(\"uh oh\");</script>",
|
"xss": "<script>alert(\"uh oh\");</script>",
|
||||||
"intmap": map[int]string{
|
"intmap": map[int]string{
|
||||||
1: "one",
|
1: "one",
|
||||||
2: "two",
|
|
||||||
5: "five",
|
5: "five",
|
||||||
|
2: "two",
|
||||||
|
},
|
||||||
|
"strmap": map[string]string{
|
||||||
|
"abc": "def",
|
||||||
|
"bcd": "efg",
|
||||||
|
"zab": "cde",
|
||||||
|
"gh": "kqm",
|
||||||
|
"ukq": "qqa",
|
||||||
|
"aab": "aba",
|
||||||
},
|
},
|
||||||
"func_add": func(a, b int) int {
|
"func_add": func(a, b int) int {
|
||||||
return a + b
|
return a + b
|
||||||
|
@ -167,17 +158,17 @@ Yep!`,
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
},
|
},
|
||||||
"func_variadic_sum_int2": func(args ...*Value) *Value {
|
"func_variadic_sum_int2": func(args ...*pongo2.Value) *pongo2.Value {
|
||||||
// Create a sum
|
// Create a sum
|
||||||
s := 0
|
s := 0
|
||||||
for _, i := range args {
|
for _, i := range args {
|
||||||
s += i.Integer()
|
s += i.Integer()
|
||||||
}
|
}
|
||||||
return AsValue(s)
|
return pongo2.AsValue(s)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"complex": map[string]interface{}{
|
"complex": map[string]interface{}{
|
||||||
"is_admin": is_admin,
|
"is_admin": isAdmin,
|
||||||
"post": post{
|
"post": post{
|
||||||
Text: "<h2>Hello!</h2><p>Welcome to my new blog page. I'm using pongo2 which supports {{ variables }} and {% tags %}.</p>",
|
Text: "<h2>Hello!</h2><p>Welcome to my new blog page. I'm using pongo2 which supports {{ variables }} and {% tags %}.</p>",
|
||||||
Created: time2,
|
Created: time2,
|
||||||
|
@ -238,10 +229,8 @@ Yep!`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTemplates(t *testing.T) {
|
func TestTemplates(t *testing.T) {
|
||||||
debug = true
|
|
||||||
|
|
||||||
// Add a global to the default set
|
// Add a global to the default set
|
||||||
Globals["this_is_a_global_variable"] = "this is a global text"
|
pongo2.Globals["this_is_a_global_variable"] = "this is a global text"
|
||||||
|
|
||||||
matches, err := filepath.Glob("./template_tests/*.tpl")
|
matches, err := filepath.Glob("./template_tests/*.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -249,34 +238,34 @@ func TestTemplates(t *testing.T) {
|
||||||
}
|
}
|
||||||
for idx, match := range matches {
|
for idx, match := range matches {
|
||||||
t.Logf("[Template %3d] Testing '%s'", idx+1, match)
|
t.Logf("[Template %3d] Testing '%s'", idx+1, match)
|
||||||
tpl, err := FromFile(match)
|
tpl, err := pongo2.FromFile(match)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error on FromFile('%s'): %s", match, err.Error())
|
t.Fatalf("Error on FromFile('%s'): %s", match, err.Error())
|
||||||
}
|
}
|
||||||
test_filename := fmt.Sprintf("%s.out", match)
|
testFilename := fmt.Sprintf("%s.out", match)
|
||||||
test_out, rerr := ioutil.ReadFile(test_filename)
|
testOut, rerr := ioutil.ReadFile(testFilename)
|
||||||
if rerr != nil {
|
if rerr != nil {
|
||||||
t.Fatalf("Error on ReadFile('%s'): %s", test_filename, rerr.Error())
|
t.Fatalf("Error on ReadFile('%s'): %s", testFilename, rerr.Error())
|
||||||
}
|
}
|
||||||
tpl_out, err := tpl.ExecuteBytes(tplContext)
|
tplOut, err := tpl.ExecuteBytes(tplContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error on Execute('%s'): %s", match, err.Error())
|
t.Fatalf("Error on Execute('%s'): %s", match, err.Error())
|
||||||
}
|
}
|
||||||
if bytes.Compare(test_out, tpl_out) != 0 {
|
if bytes.Compare(testOut, tplOut) != 0 {
|
||||||
t.Logf("Template (rendered) '%s': '%s'", match, tpl_out)
|
t.Logf("Template (rendered) '%s': '%s'", match, tplOut)
|
||||||
err_filename := filepath.Base(fmt.Sprintf("%s.error", match))
|
errFilename := filepath.Base(fmt.Sprintf("%s.error", match))
|
||||||
err := ioutil.WriteFile(err_filename, []byte(tpl_out), 0600)
|
err := ioutil.WriteFile(errFilename, []byte(tplOut), 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(err.Error())
|
t.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
t.Logf("get a complete diff with command: 'diff -ya %s %s'", test_filename, err_filename)
|
t.Logf("get a complete diff with command: 'diff -ya %s %s'", testFilename, errFilename)
|
||||||
t.Errorf("Failed: test_out != tpl_out for %s", match)
|
t.Errorf("Failed: test_out != tpl_out for %s", match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExecutionErrors(t *testing.T) {
|
func TestExecutionErrors(t *testing.T) {
|
||||||
debug = true
|
//debug = true
|
||||||
|
|
||||||
matches, err := filepath.Glob("./template_tests/*-execution.err")
|
matches, err := filepath.Glob("./template_tests/*-execution.err")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -285,15 +274,15 @@ func TestExecutionErrors(t *testing.T) {
|
||||||
for idx, match := range matches {
|
for idx, match := range matches {
|
||||||
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
||||||
|
|
||||||
test_data, err := ioutil.ReadFile(match)
|
testData, err := ioutil.ReadFile(match)
|
||||||
tests := strings.Split(string(test_data), "\n")
|
tests := strings.Split(string(testData), "\n")
|
||||||
|
|
||||||
check_filename := fmt.Sprintf("%s.out", match)
|
checkFilename := fmt.Sprintf("%s.out", match)
|
||||||
check_data, err := ioutil.ReadFile(check_filename)
|
checkData, err := ioutil.ReadFile(checkFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error on ReadFile('%s'): %s", check_filename, err.Error())
|
t.Fatalf("Error on ReadFile('%s'): %s", checkFilename, err.Error())
|
||||||
}
|
}
|
||||||
checks := strings.Split(string(check_data), "\n")
|
checks := strings.Split(string(checkData), "\n")
|
||||||
|
|
||||||
if len(checks) != len(tests) {
|
if len(checks) != len(tests) {
|
||||||
t.Fatal("Template lines != Checks lines")
|
t.Fatal("Template lines != Checks lines")
|
||||||
|
@ -308,11 +297,16 @@ func TestExecutionErrors(t *testing.T) {
|
||||||
match, idx+1)
|
match, idx+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
tpl, err := FromString(test)
|
tpl, err := pongo2.FromString(test)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error on FromString('%s'): %s", test, err.Error())
|
t.Fatalf("Error on FromString('%s'): %s", test, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tpl, err = pongo2.FromBytes([]byte(test))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error on FromBytes('%s'): %s", test, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
_, err = tpl.ExecuteBytes(tplContext)
|
_, err = tpl.ExecuteBytes(tplContext)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("[%s Line %d] Expected error for (got none): %s",
|
t.Fatalf("[%s Line %d] Expected error for (got none): %s",
|
||||||
|
@ -329,7 +323,7 @@ func TestExecutionErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompilationErrors(t *testing.T) {
|
func TestCompilationErrors(t *testing.T) {
|
||||||
debug = true
|
//debug = true
|
||||||
|
|
||||||
matches, err := filepath.Glob("./template_tests/*-compilation.err")
|
matches, err := filepath.Glob("./template_tests/*-compilation.err")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -338,15 +332,15 @@ func TestCompilationErrors(t *testing.T) {
|
||||||
for idx, match := range matches {
|
for idx, match := range matches {
|
||||||
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
||||||
|
|
||||||
test_data, err := ioutil.ReadFile(match)
|
testData, err := ioutil.ReadFile(match)
|
||||||
tests := strings.Split(string(test_data), "\n")
|
tests := strings.Split(string(testData), "\n")
|
||||||
|
|
||||||
check_filename := fmt.Sprintf("%s.out", match)
|
checkFilename := fmt.Sprintf("%s.out", match)
|
||||||
check_data, err := ioutil.ReadFile(check_filename)
|
checkData, err := ioutil.ReadFile(checkFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error on ReadFile('%s'): %s", check_filename, err.Error())
|
t.Fatalf("Error on ReadFile('%s'): %s", checkFilename, err.Error())
|
||||||
}
|
}
|
||||||
checks := strings.Split(string(check_data), "\n")
|
checks := strings.Split(string(checkData), "\n")
|
||||||
|
|
||||||
if len(checks) != len(tests) {
|
if len(checks) != len(tests) {
|
||||||
t.Fatal("Template lines != Checks lines")
|
t.Fatal("Template lines != Checks lines")
|
||||||
|
@ -361,7 +355,7 @@ func TestCompilationErrors(t *testing.T) {
|
||||||
match, idx+1)
|
match, idx+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = FromString(test)
|
_, err = pongo2.FromString(test)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("[%s | Line %d] Expected error for (got none): %s", match, idx+1, tests[idx])
|
t.Fatalf("[%s | Line %d] Expected error for (got none): %s", match, idx+1, tests[idx])
|
||||||
}
|
}
|
||||||
|
@ -377,9 +371,10 @@ func TestCompilationErrors(t *testing.T) {
|
||||||
func TestBaseDirectory(t *testing.T) {
|
func TestBaseDirectory(t *testing.T) {
|
||||||
mustStr := "Hello from template_tests/base_dir_test/"
|
mustStr := "Hello from template_tests/base_dir_test/"
|
||||||
|
|
||||||
s := NewSet("test set with base directory")
|
fs := pongo2.MustNewLocalFileSystemLoader("")
|
||||||
|
s := pongo2.NewSet("test set with base directory", fs)
|
||||||
s.Globals["base_directory"] = "template_tests/base_dir_test/"
|
s.Globals["base_directory"] = "template_tests/base_dir_test/"
|
||||||
if err := s.SetBaseDirectory(s.Globals["base_directory"].(string)); err != nil {
|
if err := fs.SetBaseDir(s.Globals["base_directory"].(string)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,13 +400,13 @@ func TestBaseDirectory(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCache(b *testing.B) {
|
func BenchmarkCache(b *testing.B) {
|
||||||
cache_set := NewSet("cache set")
|
cacheSet := pongo2.NewSet("cache set", pongo2.MustNewLocalFileSystemLoader(""))
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
tpl, err := cache_set.FromCache("template_tests/complex.tpl")
|
tpl, err := cacheSet.FromCache("template_tests/complex.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = tpl.ExecuteBytes(tplContext)
|
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -419,14 +414,14 @@ func BenchmarkCache(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkCacheDebugOn(b *testing.B) {
|
func BenchmarkCacheDebugOn(b *testing.B) {
|
||||||
cache_debug_set := NewSet("cache set")
|
cacheDebugSet := pongo2.NewSet("cache set", pongo2.MustNewLocalFileSystemLoader(""))
|
||||||
cache_debug_set.Debug = true
|
cacheDebugSet.Debug = true
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
tpl, err := cache_debug_set.FromFile("template_tests/complex.tpl")
|
tpl, err := cacheDebugSet.FromFile("template_tests/complex.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = tpl.ExecuteBytes(tplContext)
|
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -434,13 +429,13 @@ func BenchmarkCacheDebugOn(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkExecuteComplexWithSandboxActive(b *testing.B) {
|
func BenchmarkExecuteComplexWithSandboxActive(b *testing.B) {
|
||||||
tpl, err := FromFile("template_tests/complex.tpl")
|
tpl, err := pongo2.FromFile("template_tests/complex.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err = tpl.ExecuteBytes(tplContext)
|
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -455,12 +450,12 @@ func BenchmarkCompileAndExecuteComplexWithSandboxActive(b *testing.B) {
|
||||||
preloadedTpl := string(buf)
|
preloadedTpl := string(buf)
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
tpl, err := FromString(preloadedTpl)
|
tpl, err := pongo2.FromString(preloadedTpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tpl.ExecuteBytes(tplContext)
|
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -468,14 +463,14 @@ func BenchmarkCompileAndExecuteComplexWithSandboxActive(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParallelExecuteComplexWithSandboxActive(b *testing.B) {
|
func BenchmarkParallelExecuteComplexWithSandboxActive(b *testing.B) {
|
||||||
tpl, err := FromFile("template_tests/complex.tpl")
|
tpl, err := pongo2.FromFile("template_tests/complex.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
_, err := tpl.ExecuteBytes(tplContext)
|
err := tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -484,14 +479,14 @@ func BenchmarkParallelExecuteComplexWithSandboxActive(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkExecuteComplexWithoutSandbox(b *testing.B) {
|
func BenchmarkExecuteComplexWithoutSandbox(b *testing.B) {
|
||||||
s := NewSet("set without sandbox")
|
s := pongo2.NewSet("set without sandbox", pongo2.MustNewLocalFileSystemLoader(""))
|
||||||
tpl, err := s.FromFile("template_tests/complex.tpl")
|
tpl, err := s.FromFile("template_tests/complex.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_, err = tpl.ExecuteBytes(tplContext)
|
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -505,7 +500,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
||||||
}
|
}
|
||||||
preloadedTpl := string(buf)
|
preloadedTpl := string(buf)
|
||||||
|
|
||||||
s := NewSet("set without sandbox")
|
s := pongo2.NewSet("set without sandbox", pongo2.MustNewLocalFileSystemLoader(""))
|
||||||
|
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
@ -514,7 +509,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tpl.ExecuteBytes(tplContext)
|
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -522,7 +517,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkParallelExecuteComplexWithoutSandbox(b *testing.B) {
|
func BenchmarkParallelExecuteComplexWithoutSandbox(b *testing.B) {
|
||||||
s := NewSet("set without sandbox")
|
s := pongo2.NewSet("set without sandbox", pongo2.MustNewLocalFileSystemLoader(""))
|
||||||
tpl, err := s.FromFile("template_tests/complex.tpl")
|
tpl, err := s.FromFile("template_tests/complex.tpl")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
|
@ -530,7 +525,7 @@ func BenchmarkParallelExecuteComplexWithoutSandbox(b *testing.B) {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
_, err := tpl.ExecuteBytes(tplContext)
|
err := tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
65
vendor/github.com/flosch/pongo2/pongo2_test.go
generated
vendored
65
vendor/github.com/flosch/pongo2/pongo2_test.go
generated
vendored
|
@ -1,26 +1,26 @@
|
||||||
package pongo2
|
package pongo2_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/flosch/pongo2"
|
||||||
. "gopkg.in/check.v1"
|
. "gopkg.in/check.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Hook up gocheck into the "go test" runner.
|
// Hook up gocheck into the "go test" runner.
|
||||||
|
|
||||||
func Test(t *testing.T) { TestingT(t) }
|
func Test(t *testing.T) { TestingT(t) }
|
||||||
|
|
||||||
type TestSuite struct {
|
type TestSuite struct {
|
||||||
tpl *Template
|
tpl *pongo2.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ = Suite(&TestSuite{})
|
_ = Suite(&TestSuite{})
|
||||||
test_suite2 = NewSet("test suite 2")
|
testSuite2 = pongo2.NewSet("test suite 2", pongo2.MustNewLocalFileSystemLoader(""))
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseTemplate(s string, c Context) string {
|
func parseTemplate(s string, c pongo2.Context) string {
|
||||||
t, err := test_suite2.FromString(s)
|
t, err := testSuite2.FromString(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func parseTemplate(s string, c Context) string {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTemplateFn(s string, c Context) func() {
|
func parseTemplateFn(s string, c pongo2.Context) func() {
|
||||||
return func() {
|
return func() {
|
||||||
parseTemplate(s, c)
|
parseTemplate(s, c)
|
||||||
}
|
}
|
||||||
|
@ -40,27 +40,64 @@ func parseTemplateFn(s string, c Context) func() {
|
||||||
func (s *TestSuite) TestMisc(c *C) {
|
func (s *TestSuite) TestMisc(c *C) {
|
||||||
// Must
|
// Must
|
||||||
// TODO: Add better error message (see issue #18)
|
// TODO: Add better error message (see issue #18)
|
||||||
c.Check(func() { Must(test_suite2.FromFile("template_tests/inheritance/base2.tpl")) },
|
c.Check(
|
||||||
|
func() { pongo2.Must(testSuite2.FromFile("template_tests/inheritance/base2.tpl")) },
|
||||||
PanicMatches,
|
PanicMatches,
|
||||||
`\[Error \(where: fromfile\) in template_tests/inheritance/doesnotexist.tpl | Line 1 Col 12 near 'doesnotexist.tpl'\] open template_tests/inheritance/doesnotexist.tpl: no such file or directory`)
|
`\[Error \(where: fromfile\) in .*template_tests/inheritance/doesnotexist.tpl | Line 1 Col 12 near 'doesnotexist.tpl'\] open .*template_tests/inheritance/doesnotexist.tpl: no such file or directory`,
|
||||||
|
)
|
||||||
|
|
||||||
// Context
|
// Context
|
||||||
c.Check(parseTemplateFn("", Context{"'illegal": nil}), PanicMatches, ".*not a valid identifier.*")
|
c.Check(parseTemplateFn("", pongo2.Context{"'illegal": nil}), PanicMatches, ".*not a valid identifier.*")
|
||||||
|
|
||||||
// Registers
|
// Registers
|
||||||
c.Check(func() { RegisterFilter("escape", nil) }, PanicMatches, ".*is already registered.*")
|
c.Check(pongo2.RegisterFilter("escape", nil).Error(), Matches, ".*is already registered")
|
||||||
c.Check(func() { RegisterTag("for", nil) }, PanicMatches, ".*is already registered.*")
|
c.Check(pongo2.RegisterTag("for", nil).Error(), Matches, ".*is already registered")
|
||||||
|
|
||||||
// ApplyFilter
|
// ApplyFilter
|
||||||
v, err := ApplyFilter("title", AsValue("this is a title"), nil)
|
v, err := pongo2.ApplyFilter("title", pongo2.AsValue("this is a title"), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Fatal(err)
|
c.Fatal(err)
|
||||||
}
|
}
|
||||||
c.Check(v.String(), Equals, "This Is A Title")
|
c.Check(v.String(), Equals, "This Is A Title")
|
||||||
c.Check(func() {
|
c.Check(func() {
|
||||||
_, err := ApplyFilter("doesnotexist", nil, nil)
|
_, err := pongo2.ApplyFilter("doesnotexist", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}, PanicMatches, `\[Error \(where: applyfilter\)\] Filter with name 'doesnotexist' not found.`)
|
}, PanicMatches, `\[Error \(where: applyfilter\)\] Filter with name 'doesnotexist' not found.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TestSuite) TestImplicitExecCtx(c *C) {
|
||||||
|
tpl, err := pongo2.FromString("{{ ImplicitExec }}")
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Error in FromString: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
val := "a stringy thing"
|
||||||
|
|
||||||
|
res, err := tpl.Execute(pongo2.Context{
|
||||||
|
"Value": val,
|
||||||
|
"ImplicitExec": func(ctx *pongo2.ExecutionContext) string {
|
||||||
|
return ctx.Public["Value"].(string)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Error executing template: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Check(res, Equals, val)
|
||||||
|
|
||||||
|
// The implicit ctx should not be persisted from call-to-call
|
||||||
|
res, err = tpl.Execute(pongo2.Context{
|
||||||
|
"ImplicitExec": func() string {
|
||||||
|
return val
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.Fatalf("Error executing template: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Check(res, Equals, val)
|
||||||
|
}
|
||||||
|
|
41
vendor/github.com/flosch/pongo2/tags.go
generated
vendored
41
vendor/github.com/flosch/pongo2/tags.go
generated
vendored
|
@ -21,6 +21,8 @@ package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type INodeTag interface {
|
type INodeTag interface {
|
||||||
|
@ -53,80 +55,81 @@ func init() {
|
||||||
tags = make(map[string]*tag)
|
tags = make(map[string]*tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registers a new tag. If there's already a tag with the same
|
// Registers a new tag. You usually want to call this
|
||||||
// name, RegisterTag will panic. You usually want to call this
|
|
||||||
// function in the tag's init() function:
|
// function in the tag's init() function:
|
||||||
// http://golang.org/doc/effective_go.html#init
|
// http://golang.org/doc/effective_go.html#init
|
||||||
//
|
//
|
||||||
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
||||||
// writing filters and tags.
|
// writing filters and tags.
|
||||||
func RegisterTag(name string, parserFn TagParser) {
|
func RegisterTag(name string, parserFn TagParser) error {
|
||||||
_, existing := tags[name]
|
_, existing := tags[name]
|
||||||
if existing {
|
if existing {
|
||||||
panic(fmt.Sprintf("Tag with name '%s' is already registered.", name))
|
return errors.Errorf("tag with name '%s' is already registered", name)
|
||||||
}
|
}
|
||||||
tags[name] = &tag{
|
tags[name] = &tag{
|
||||||
name: name,
|
name: name,
|
||||||
parser: parserFn,
|
parser: parserFn,
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces an already registered tag with a new implementation. Use this
|
// Replaces an already registered tag with a new implementation. Use this
|
||||||
// function with caution since it allows you to change existing tag behaviour.
|
// function with caution since it allows you to change existing tag behaviour.
|
||||||
func ReplaceTag(name string, parserFn TagParser) {
|
func ReplaceTag(name string, parserFn TagParser) error {
|
||||||
_, existing := tags[name]
|
_, existing := tags[name]
|
||||||
if !existing {
|
if !existing {
|
||||||
panic(fmt.Sprintf("Tag with name '%s' does not exist (therefore cannot be overridden).", name))
|
return errors.Errorf("tag with name '%s' does not exist (therefore cannot be overridden)", name)
|
||||||
}
|
}
|
||||||
tags[name] = &tag{
|
tags[name] = &tag{
|
||||||
name: name,
|
name: name,
|
||||||
parser: parserFn,
|
parser: parserFn,
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag = "{%" IDENT ARGS "%}"
|
// Tag = "{%" IDENT ARGS "%}"
|
||||||
func (p *Parser) parseTagElement() (INodeTag, *Error) {
|
func (p *Parser) parseTagElement() (INodeTag, *Error) {
|
||||||
p.Consume() // consume "{%"
|
p.Consume() // consume "{%"
|
||||||
token_name := p.MatchType(TokenIdentifier)
|
tokenName := p.MatchType(TokenIdentifier)
|
||||||
|
|
||||||
// Check for identifier
|
// Check for identifier
|
||||||
if token_name == nil {
|
if tokenName == nil {
|
||||||
return nil, p.Error("Tag name must be an identifier.", nil)
|
return nil, p.Error("Tag name must be an identifier.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for the existing tag
|
// Check for the existing tag
|
||||||
tag, exists := tags[token_name.Val]
|
tag, exists := tags[tokenName.Val]
|
||||||
if !exists {
|
if !exists {
|
||||||
// Does not exists
|
// Does not exists
|
||||||
return nil, p.Error(fmt.Sprintf("Tag '%s' not found (or beginning tag not provided)", token_name.Val), token_name)
|
return nil, p.Error(fmt.Sprintf("Tag '%s' not found (or beginning tag not provided)", tokenName.Val), tokenName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sandbox tag restriction
|
// Check sandbox tag restriction
|
||||||
if _, is_banned := p.template.set.bannedTags[token_name.Val]; is_banned {
|
if _, isBanned := p.template.set.bannedTags[tokenName.Val]; isBanned {
|
||||||
return nil, p.Error(fmt.Sprintf("Usage of tag '%s' is not allowed (sandbox restriction active).", token_name.Val), token_name)
|
return nil, p.Error(fmt.Sprintf("Usage of tag '%s' is not allowed (sandbox restriction active).", tokenName.Val), tokenName)
|
||||||
}
|
}
|
||||||
|
|
||||||
args_token := make([]*Token, 0)
|
var argsToken []*Token
|
||||||
for p.Peek(TokenSymbol, "%}") == nil && p.Remaining() > 0 {
|
for p.Peek(TokenSymbol, "%}") == nil && p.Remaining() > 0 {
|
||||||
// Add token to args
|
// Add token to args
|
||||||
args_token = append(args_token, p.Current())
|
argsToken = append(argsToken, p.Current())
|
||||||
p.Consume() // next token
|
p.Consume() // next token
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF?
|
// EOF?
|
||||||
if p.Remaining() == 0 {
|
if p.Remaining() == 0 {
|
||||||
return nil, p.Error("Unexpectedly reached EOF, no tag end found.", p.last_token)
|
return nil, p.Error("Unexpectedly reached EOF, no tag end found.", p.lastToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Match(TokenSymbol, "%}")
|
p.Match(TokenSymbol, "%}")
|
||||||
|
|
||||||
arg_parser := newParser(p.name, args_token, p.template)
|
argParser := newParser(p.name, argsToken, p.template)
|
||||||
if len(args_token) == 0 {
|
if len(argsToken) == 0 {
|
||||||
// This is done to have nice EOF error messages
|
// This is done to have nice EOF error messages
|
||||||
arg_parser.last_token = token_name
|
argParser.lastToken = tokenName
|
||||||
}
|
}
|
||||||
|
|
||||||
p.template.level++
|
p.template.level++
|
||||||
defer func() { p.template.level-- }()
|
defer func() { p.template.level-- }()
|
||||||
return tag.parser(p, token_name, arg_parser)
|
return tag.parser(p, tokenName, argParser)
|
||||||
}
|
}
|
||||||
|
|
26
vendor/github.com/flosch/pongo2/tags_autoescape.go
generated
vendored
26
vendor/github.com/flosch/pongo2/tags_autoescape.go
generated
vendored
|
@ -1,19 +1,15 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagAutoescapeNode struct {
|
type tagAutoescapeNode struct {
|
||||||
wrapper *NodeWrapper
|
wrapper *NodeWrapper
|
||||||
autoescape bool
|
autoescape bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
old := ctx.Autoescape
|
old := ctx.Autoescape
|
||||||
ctx.Autoescape = node.autoescape
|
ctx.Autoescape = node.autoescape
|
||||||
|
|
||||||
err := node.wrapper.Execute(ctx, buffer)
|
err := node.wrapper.Execute(ctx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -24,22 +20,22 @@ func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buff
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagAutoescapeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagAutoescapeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
autoescape_node := &tagAutoescapeNode{}
|
autoescapeNode := &tagAutoescapeNode{}
|
||||||
|
|
||||||
wrapper, _, err := doc.WrapUntilTag("endautoescape")
|
wrapper, _, err := doc.WrapUntilTag("endautoescape")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
autoescape_node.wrapper = wrapper
|
autoescapeNode.wrapper = wrapper
|
||||||
|
|
||||||
mode_token := arguments.MatchType(TokenIdentifier)
|
modeToken := arguments.MatchType(TokenIdentifier)
|
||||||
if mode_token == nil {
|
if modeToken == nil {
|
||||||
return nil, arguments.Error("A mode is required for autoescape-tag.", nil)
|
return nil, arguments.Error("A mode is required for autoescape-tag.", nil)
|
||||||
}
|
}
|
||||||
if mode_token.Val == "on" {
|
if modeToken.Val == "on" {
|
||||||
autoescape_node.autoescape = true
|
autoescapeNode.autoescape = true
|
||||||
} else if mode_token.Val == "off" {
|
} else if modeToken.Val == "off" {
|
||||||
autoescape_node.autoescape = false
|
autoescapeNode.autoescape = false
|
||||||
} else {
|
} else {
|
||||||
return nil, arguments.Error("Only 'on' or 'off' is valid as an autoescape-mode.", nil)
|
return nil, arguments.Error("Only 'on' or 'off' is valid as an autoescape-mode.", nil)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +44,7 @@ func tagAutoescapeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
||||||
return nil, arguments.Error("Malformed autoescape-tag arguments.", nil)
|
return nil, arguments.Error("Malformed autoescape-tag arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return autoescape_node, nil
|
return autoescapeNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
91
vendor/github.com/flosch/pongo2/tags_block.go
generated
vendored
91
vendor/github.com/flosch/pongo2/tags_block.go
generated
vendored
|
@ -9,47 +9,82 @@ type tagBlockNode struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagBlockNode) getBlockWrapperByName(tpl *Template) *NodeWrapper {
|
func (node *tagBlockNode) getBlockWrappers(tpl *Template) []*NodeWrapper {
|
||||||
|
nodeWrappers := make([]*NodeWrapper, 0)
|
||||||
var t *NodeWrapper
|
var t *NodeWrapper
|
||||||
if tpl.child != nil {
|
|
||||||
// First ask the child for the block
|
for tpl != nil {
|
||||||
t = node.getBlockWrapperByName(tpl.child)
|
|
||||||
}
|
|
||||||
if t == nil {
|
|
||||||
// Child has no block, lets look up here at parent
|
|
||||||
t = tpl.blocks[node.name]
|
t = tpl.blocks[node.name]
|
||||||
|
if t != nil {
|
||||||
|
nodeWrappers = append(nodeWrappers, t)
|
||||||
}
|
}
|
||||||
return t
|
tpl = tpl.child
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeWrappers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagBlockNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagBlockNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
tpl := ctx.template
|
tpl := ctx.template
|
||||||
if tpl == nil {
|
if tpl == nil {
|
||||||
panic("internal error: tpl == nil")
|
panic("internal error: tpl == nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the block to execute
|
// Determine the block to execute
|
||||||
block_wrapper := node.getBlockWrapperByName(tpl)
|
blockWrappers := node.getBlockWrappers(tpl)
|
||||||
if block_wrapper == nil {
|
lenBlockWrappers := len(blockWrappers)
|
||||||
// fmt.Printf("could not find: %s\n", node.name)
|
|
||||||
return ctx.Error("internal error: block_wrapper == nil in tagBlockNode.Execute()", nil)
|
if lenBlockWrappers == 0 {
|
||||||
|
return ctx.Error("internal error: len(block_wrappers) == 0 in tagBlockNode.Execute()", nil)
|
||||||
}
|
}
|
||||||
err := block_wrapper.Execute(ctx, buffer)
|
|
||||||
|
blockWrapper := blockWrappers[lenBlockWrappers-1]
|
||||||
|
ctx.Private["block"] = tagBlockInformation{
|
||||||
|
ctx: ctx,
|
||||||
|
wrappers: blockWrappers[0 : lenBlockWrappers-1],
|
||||||
|
}
|
||||||
|
err := blockWrapper.Execute(ctx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add support for {{ block.super }}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tagBlockInformation struct {
|
||||||
|
ctx *ExecutionContext
|
||||||
|
wrappers []*NodeWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t tagBlockInformation) Super() string {
|
||||||
|
lenWrappers := len(t.wrappers)
|
||||||
|
|
||||||
|
if lenWrappers == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
superCtx := NewChildExecutionContext(t.ctx)
|
||||||
|
superCtx.Private["block"] = tagBlockInformation{
|
||||||
|
ctx: t.ctx,
|
||||||
|
wrappers: t.wrappers[0 : lenWrappers-1],
|
||||||
|
}
|
||||||
|
|
||||||
|
blockWrapper := t.wrappers[lenWrappers-1]
|
||||||
|
buf := bytes.NewBufferString("")
|
||||||
|
err := blockWrapper.Execute(superCtx, &templateWriter{buf})
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
func tagBlockParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagBlockParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
if arguments.Count() == 0 {
|
if arguments.Count() == 0 {
|
||||||
return nil, arguments.Error("Tag 'block' requires an identifier.", nil)
|
return nil, arguments.Error("Tag 'block' requires an identifier.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
name_token := arguments.MatchType(TokenIdentifier)
|
nameToken := arguments.MatchType(TokenIdentifier)
|
||||||
if name_token == nil {
|
if nameToken == nil {
|
||||||
return nil, arguments.Error("First argument for tag 'block' must be an identifier.", nil)
|
return nil, arguments.Error("First argument for tag 'block' must be an identifier.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,15 +97,15 @@ func tagBlockParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if endtagargs.Remaining() > 0 {
|
if endtagargs.Remaining() > 0 {
|
||||||
endtagname_token := endtagargs.MatchType(TokenIdentifier)
|
endtagnameToken := endtagargs.MatchType(TokenIdentifier)
|
||||||
if endtagname_token != nil {
|
if endtagnameToken != nil {
|
||||||
if endtagname_token.Val != name_token.Val {
|
if endtagnameToken.Val != nameToken.Val {
|
||||||
return nil, endtagargs.Error(fmt.Sprintf("Name for 'endblock' must equal to 'block'-tag's name ('%s' != '%s').",
|
return nil, endtagargs.Error(fmt.Sprintf("Name for 'endblock' must equal to 'block'-tag's name ('%s' != '%s').",
|
||||||
name_token.Val, endtagname_token.Val), nil)
|
nameToken.Val, endtagnameToken.Val), nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if endtagname_token == nil || endtagargs.Remaining() > 0 {
|
if endtagnameToken == nil || endtagargs.Remaining() > 0 {
|
||||||
return nil, endtagargs.Error("Either no or only one argument (identifier) allowed for 'endblock'.", nil)
|
return nil, endtagargs.Error("Either no or only one argument (identifier) allowed for 'endblock'.", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,14 +114,14 @@ func tagBlockParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
||||||
if tpl == nil {
|
if tpl == nil {
|
||||||
panic("internal error: tpl == nil")
|
panic("internal error: tpl == nil")
|
||||||
}
|
}
|
||||||
_, has_block := tpl.blocks[name_token.Val]
|
_, hasBlock := tpl.blocks[nameToken.Val]
|
||||||
if !has_block {
|
if !hasBlock {
|
||||||
tpl.blocks[name_token.Val] = wrapper
|
tpl.blocks[nameToken.Val] = wrapper
|
||||||
} else {
|
} else {
|
||||||
return nil, arguments.Error(fmt.Sprintf("Block named '%s' already defined", name_token.Val), nil)
|
return nil, arguments.Error(fmt.Sprintf("Block named '%s' already defined", nameToken.Val), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &tagBlockNode{name: name_token.Val}, nil
|
return &tagBlockNode{name: nameToken.Val}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
12
vendor/github.com/flosch/pongo2/tags_comment.go
generated
vendored
12
vendor/github.com/flosch/pongo2/tags_comment.go
generated
vendored
|
@ -1,20 +1,16 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagCommentNode struct{}
|
type tagCommentNode struct{}
|
||||||
|
|
||||||
func (node *tagCommentNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagCommentNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagCommentParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagCommentParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
comment_node := &tagCommentNode{}
|
commentNode := &tagCommentNode{}
|
||||||
|
|
||||||
// TODO: Process the endtag's arguments (see django 'comment'-tag documentation)
|
// TODO: Process the endtag's arguments (see django 'comment'-tag documentation)
|
||||||
_, _, err := doc.WrapUntilTag("endcomment")
|
err := doc.SkipUntilTag("endcomment")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -23,7 +19,7 @@ func tagCommentParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
return nil, arguments.Error("Tag 'comment' does not take any argument.", nil)
|
return nil, arguments.Error("Tag 'comment' does not take any argument.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return comment_node, nil
|
return commentNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
34
vendor/github.com/flosch/pongo2/tags_cycle.go
generated
vendored
34
vendor/github.com/flosch/pongo2/tags_cycle.go
generated
vendored
|
@ -1,9 +1,5 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagCycleValue struct {
|
type tagCycleValue struct {
|
||||||
node *tagCycleNode
|
node *tagCycleNode
|
||||||
value *Value
|
value *Value
|
||||||
|
@ -13,7 +9,7 @@ type tagCycleNode struct {
|
||||||
position *Token
|
position *Token
|
||||||
args []IEvaluator
|
args []IEvaluator
|
||||||
idx int
|
idx int
|
||||||
as_name string
|
asName string
|
||||||
silent bool
|
silent bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +17,7 @@ func (cv *tagCycleValue) String() string {
|
||||||
return cv.value.String()
|
return cv.value.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagCycleNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagCycleNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
item := node.args[node.idx%len(node.args)]
|
item := node.args[node.idx%len(node.args)]
|
||||||
node.idx++
|
node.idx++
|
||||||
|
|
||||||
|
@ -46,30 +42,30 @@ func (node *tagCycleNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *
|
||||||
t.value = val
|
t.value = val
|
||||||
|
|
||||||
if !t.node.silent {
|
if !t.node.silent {
|
||||||
buffer.WriteString(val.String())
|
writer.WriteString(val.String())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Regular call
|
// Regular call
|
||||||
|
|
||||||
cycle_value := &tagCycleValue{
|
cycleValue := &tagCycleValue{
|
||||||
node: node,
|
node: node,
|
||||||
value: val,
|
value: val,
|
||||||
}
|
}
|
||||||
|
|
||||||
if node.as_name != "" {
|
if node.asName != "" {
|
||||||
ctx.Private[node.as_name] = cycle_value
|
ctx.Private[node.asName] = cycleValue
|
||||||
}
|
}
|
||||||
if !node.silent {
|
if !node.silent {
|
||||||
buffer.WriteString(val.String())
|
writer.WriteString(val.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HINT: We're not supporting the old comma-seperated list of expresions argument-style
|
// HINT: We're not supporting the old comma-separated list of expressions argument-style
|
||||||
func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
cycle_node := &tagCycleNode{
|
cycleNode := &tagCycleNode{
|
||||||
position: start,
|
position: start,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,19 +74,19 @@ func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cycle_node.args = append(cycle_node.args, node)
|
cycleNode.args = append(cycleNode.args, node)
|
||||||
|
|
||||||
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
||||||
// as
|
// as
|
||||||
|
|
||||||
name_token := arguments.MatchType(TokenIdentifier)
|
nameToken := arguments.MatchType(TokenIdentifier)
|
||||||
if name_token == nil {
|
if nameToken == nil {
|
||||||
return nil, arguments.Error("Name (identifier) expected after 'as'.", nil)
|
return nil, arguments.Error("Name (identifier) expected after 'as'.", nil)
|
||||||
}
|
}
|
||||||
cycle_node.as_name = name_token.Val
|
cycleNode.asName = nameToken.Val
|
||||||
|
|
||||||
if arguments.MatchOne(TokenIdentifier, "silent") != nil {
|
if arguments.MatchOne(TokenIdentifier, "silent") != nil {
|
||||||
cycle_node.silent = true
|
cycleNode.silent = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we're finished
|
// Now we're finished
|
||||||
|
@ -102,7 +98,7 @@ func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
||||||
return nil, arguments.Error("Malformed cycle-tag.", nil)
|
return nil, arguments.Error("Malformed cycle-tag.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cycle_node, nil
|
return cycleNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
22
vendor/github.com/flosch/pongo2/tags_extends.go
generated
vendored
22
vendor/github.com/flosch/pongo2/tags_extends.go
generated
vendored
|
@ -1,19 +1,15 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagExtendsNode struct {
|
type tagExtendsNode struct {
|
||||||
filename string
|
filename string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagExtendsNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagExtendsNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
extends_node := &tagExtendsNode{}
|
extendsNode := &tagExtendsNode{}
|
||||||
|
|
||||||
if doc.template.level > 1 {
|
if doc.template.level > 1 {
|
||||||
return nil, arguments.Error("The 'extends' tag can only defined on root level.", start)
|
return nil, arguments.Error("The 'extends' tag can only defined on root level.", start)
|
||||||
|
@ -24,22 +20,22 @@ func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
return nil, arguments.Error("This template has already one parent.", start)
|
return nil, arguments.Error("This template has already one parent.", start)
|
||||||
}
|
}
|
||||||
|
|
||||||
if filename_token := arguments.MatchType(TokenString); filename_token != nil {
|
if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
|
||||||
// prepared, static template
|
// prepared, static template
|
||||||
|
|
||||||
// Get parent's filename
|
// Get parent's filename
|
||||||
parent_filename := doc.template.set.resolveFilename(doc.template, filename_token.Val)
|
parentFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
|
||||||
|
|
||||||
// Parse the parent
|
// Parse the parent
|
||||||
parent_template, err := doc.template.set.FromFile(parent_filename)
|
parentTemplate, err := doc.template.set.FromFile(parentFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.(*Error)
|
return nil, err.(*Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep track of things
|
// Keep track of things
|
||||||
parent_template.child = doc.template
|
parentTemplate.child = doc.template
|
||||||
doc.template.parent = parent_template
|
doc.template.parent = parentTemplate
|
||||||
extends_node.filename = parent_filename
|
extendsNode.filename = parentFilename
|
||||||
} else {
|
} else {
|
||||||
return nil, arguments.Error("Tag 'extends' requires a template filename as string.", nil)
|
return nil, arguments.Error("Tag 'extends' requires a template filename as string.", nil)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +44,7 @@ func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
return nil, arguments.Error("Tag 'extends' does only take 1 argument.", nil)
|
return nil, arguments.Error("Tag 'extends' does only take 1 argument.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return extends_node, nil
|
return extendsNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
26
vendor/github.com/flosch/pongo2/tags_filter.go
generated
vendored
26
vendor/github.com/flosch/pongo2/tags_filter.go
generated
vendored
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
type nodeFilterCall struct {
|
type nodeFilterCall struct {
|
||||||
name string
|
name string
|
||||||
param_expr IEvaluator
|
paramExpr IEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
type tagFilterNode struct {
|
type tagFilterNode struct {
|
||||||
|
@ -15,7 +15,7 @@ type tagFilterNode struct {
|
||||||
filterChain []*nodeFilterCall
|
filterChain []*nodeFilterCall
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagFilterNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagFilterNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
temp := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB size
|
temp := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB size
|
||||||
|
|
||||||
err := node.bodyWrapper.Execute(ctx, temp)
|
err := node.bodyWrapper.Execute(ctx, temp)
|
||||||
|
@ -27,8 +27,8 @@ func (node *tagFilterNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
||||||
|
|
||||||
for _, call := range node.filterChain {
|
for _, call := range node.filterChain {
|
||||||
var param *Value
|
var param *Value
|
||||||
if call.param_expr != nil {
|
if call.paramExpr != nil {
|
||||||
param, err = call.param_expr.Evaluate(ctx)
|
param, err = call.paramExpr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,13 @@ func (node *tagFilterNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
filter_node := &tagFilterNode{
|
filterNode := &tagFilterNode{
|
||||||
position: start,
|
position: start,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,16 +55,16 @@ func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
filter_node.bodyWrapper = wrapper
|
filterNode.bodyWrapper = wrapper
|
||||||
|
|
||||||
for arguments.Remaining() > 0 {
|
for arguments.Remaining() > 0 {
|
||||||
filterCall := &nodeFilterCall{}
|
filterCall := &nodeFilterCall{}
|
||||||
|
|
||||||
name_token := arguments.MatchType(TokenIdentifier)
|
nameToken := arguments.MatchType(TokenIdentifier)
|
||||||
if name_token == nil {
|
if nameToken == nil {
|
||||||
return nil, arguments.Error("Expected a filter name (identifier).", nil)
|
return nil, arguments.Error("Expected a filter name (identifier).", nil)
|
||||||
}
|
}
|
||||||
filterCall.name = name_token.Val
|
filterCall.name = nameToken.Val
|
||||||
|
|
||||||
if arguments.MatchOne(TokenSymbol, ":") != nil {
|
if arguments.MatchOne(TokenSymbol, ":") != nil {
|
||||||
// Filter parameter
|
// Filter parameter
|
||||||
|
@ -73,10 +73,10 @@ func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
filterCall.param_expr = expr
|
filterCall.paramExpr = expr
|
||||||
}
|
}
|
||||||
|
|
||||||
filter_node.filterChain = append(filter_node.filterChain, filterCall)
|
filterNode.filterChain = append(filterNode.filterChain, filterCall)
|
||||||
|
|
||||||
if arguments.MatchOne(TokenSymbol, "|") == nil {
|
if arguments.MatchOne(TokenSymbol, "|") == nil {
|
||||||
break
|
break
|
||||||
|
@ -87,7 +87,7 @@ func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
||||||
return nil, arguments.Error("Malformed filter-tag arguments.", nil)
|
return nil, arguments.Error("Malformed filter-tag arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return filter_node, nil
|
return filterNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
14
vendor/github.com/flosch/pongo2/tags_firstof.go
generated
vendored
14
vendor/github.com/flosch/pongo2/tags_firstof.go
generated
vendored
|
@ -1,15 +1,11 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagFirstofNode struct {
|
type tagFirstofNode struct {
|
||||||
position *Token
|
position *Token
|
||||||
args []IEvaluator
|
args []IEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagFirstofNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagFirstofNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
for _, arg := range node.args {
|
for _, arg := range node.args {
|
||||||
val, err := arg.Evaluate(ctx)
|
val, err := arg.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -24,7 +20,7 @@ func (node *tagFirstofNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(val.String())
|
writer.WriteString(val.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +29,7 @@ func (node *tagFirstofNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
firstof_node := &tagFirstofNode{
|
firstofNode := &tagFirstofNode{
|
||||||
position: start,
|
position: start,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,10 +38,10 @@ func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
firstof_node.args = append(firstof_node.args, node)
|
firstofNode.args = append(firstofNode.args, node)
|
||||||
}
|
}
|
||||||
|
|
||||||
return firstof_node, nil
|
return firstofNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
53
vendor/github.com/flosch/pongo2/tags_for.go
generated
vendored
53
vendor/github.com/flosch/pongo2/tags_for.go
generated
vendored
|
@ -1,14 +1,11 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagForNode struct {
|
type tagForNode struct {
|
||||||
key string
|
key string
|
||||||
value string // only for maps: for key, value in map
|
value string // only for maps: for key, value in map
|
||||||
object_evaluator IEvaluator
|
objectEvaluator IEvaluator
|
||||||
reversed bool
|
reversed bool
|
||||||
|
sorted bool
|
||||||
|
|
||||||
bodyWrapper *NodeWrapper
|
bodyWrapper *NodeWrapper
|
||||||
emptyWrapper *NodeWrapper
|
emptyWrapper *NodeWrapper
|
||||||
|
@ -24,7 +21,7 @@ type tagForLoopInformation struct {
|
||||||
Parentloop *tagForLoopInformation
|
Parentloop *tagForLoopInformation
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagForNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) (forError *Error) {
|
func (node *tagForNode) Execute(ctx *ExecutionContext, writer TemplateWriter) (forError *Error) {
|
||||||
// Backup forloop (as parentloop in public context), key-name and value-name
|
// Backup forloop (as parentloop in public context), key-name and value-name
|
||||||
forCtx := NewChildExecutionContext(ctx)
|
forCtx := NewChildExecutionContext(ctx)
|
||||||
parentloop := forCtx.Private["forloop"]
|
parentloop := forCtx.Private["forloop"]
|
||||||
|
@ -42,7 +39,7 @@ func (node *tagForNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) (fo
|
||||||
// Register loopInfo in public context
|
// Register loopInfo in public context
|
||||||
forCtx.Private["forloop"] = loopInfo
|
forCtx.Private["forloop"] = loopInfo
|
||||||
|
|
||||||
obj, err := node.object_evaluator.Evaluate(forCtx)
|
obj, err := node.objectEvaluator.Evaluate(forCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -67,7 +64,7 @@ func (node *tagForNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) (fo
|
||||||
loopInfo.Revcounter0 = count - (idx + 1) // TODO: Not sure about this, have to look it up
|
loopInfo.Revcounter0 = count - (idx + 1) // TODO: Not sure about this, have to look it up
|
||||||
|
|
||||||
// Render elements with updated context
|
// Render elements with updated context
|
||||||
err := node.bodyWrapper.Execute(forCtx, buffer)
|
err := node.bodyWrapper.Execute(forCtx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
forError = err
|
forError = err
|
||||||
return false
|
return false
|
||||||
|
@ -76,30 +73,30 @@ func (node *tagForNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) (fo
|
||||||
}, func() {
|
}, func() {
|
||||||
// Nothing to iterate over (maybe wrong type or no items)
|
// Nothing to iterate over (maybe wrong type or no items)
|
||||||
if node.emptyWrapper != nil {
|
if node.emptyWrapper != nil {
|
||||||
err := node.emptyWrapper.Execute(forCtx, buffer)
|
err := node.emptyWrapper.Execute(forCtx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
forError = err
|
forError = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, node.reversed)
|
}, node.reversed, node.sorted)
|
||||||
|
|
||||||
return nil
|
return forError
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
for_node := &tagForNode{}
|
forNode := &tagForNode{}
|
||||||
|
|
||||||
// Arguments parsing
|
// Arguments parsing
|
||||||
var value_token *Token
|
var valueToken *Token
|
||||||
key_token := arguments.MatchType(TokenIdentifier)
|
keyToken := arguments.MatchType(TokenIdentifier)
|
||||||
if key_token == nil {
|
if keyToken == nil {
|
||||||
return nil, arguments.Error("Expected an key identifier as first argument for 'for'-tag", nil)
|
return nil, arguments.Error("Expected an key identifier as first argument for 'for'-tag", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Match(TokenSymbol, ",") != nil {
|
if arguments.Match(TokenSymbol, ",") != nil {
|
||||||
// Value name is provided
|
// Value name is provided
|
||||||
value_token = arguments.MatchType(TokenIdentifier)
|
valueToken = arguments.MatchType(TokenIdentifier)
|
||||||
if value_token == nil {
|
if valueToken == nil {
|
||||||
return nil, arguments.Error("Value name must be an identifier.", nil)
|
return nil, arguments.Error("Value name must be an identifier.", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,18 +105,22 @@ func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Erro
|
||||||
return nil, arguments.Error("Expected keyword 'in'.", nil)
|
return nil, arguments.Error("Expected keyword 'in'.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
object_evaluator, err := arguments.ParseExpression()
|
objectEvaluator, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for_node.object_evaluator = object_evaluator
|
forNode.objectEvaluator = objectEvaluator
|
||||||
for_node.key = key_token.Val
|
forNode.key = keyToken.Val
|
||||||
if value_token != nil {
|
if valueToken != nil {
|
||||||
for_node.value = value_token.Val
|
forNode.value = valueToken.Val
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.MatchOne(TokenIdentifier, "reversed") != nil {
|
if arguments.MatchOne(TokenIdentifier, "reversed") != nil {
|
||||||
for_node.reversed = true
|
forNode.reversed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if arguments.MatchOne(TokenIdentifier, "sorted") != nil {
|
||||||
|
forNode.sorted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
|
@ -131,7 +132,7 @@ func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for_node.bodyWrapper = wrapper
|
forNode.bodyWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
|
@ -143,14 +144,14 @@ func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for_node.emptyWrapper = wrapper
|
forNode.emptyWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return for_node, nil
|
return forNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
35
vendor/github.com/flosch/pongo2/tags_if.go
generated
vendored
35
vendor/github.com/flosch/pongo2/tags_if.go
generated
vendored
|
@ -1,15 +1,11 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagIfNode struct {
|
type tagIfNode struct {
|
||||||
conditions []IEvaluator
|
conditions []IEvaluator
|
||||||
wrappers []*NodeWrapper
|
wrappers []*NodeWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagIfNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagIfNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
for i, condition := range node.conditions {
|
for i, condition := range node.conditions {
|
||||||
result, err := condition.Evaluate(ctx)
|
result, err := condition.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -17,26 +13,25 @@ func (node *tagIfNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Err
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.IsTrue() {
|
if result.IsTrue() {
|
||||||
return node.wrappers[i].Execute(ctx, buffer)
|
return node.wrappers[i].Execute(ctx, writer)
|
||||||
} else {
|
}
|
||||||
// Last condition?
|
// Last condition?
|
||||||
if len(node.conditions) == i+1 && len(node.wrappers) > i+1 {
|
if len(node.conditions) == i+1 && len(node.wrappers) > i+1 {
|
||||||
return node.wrappers[i+1].Execute(ctx, buffer)
|
return node.wrappers[i+1].Execute(ctx, writer)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagIfParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagIfParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
if_node := &tagIfNode{}
|
ifNode := &tagIfNode{}
|
||||||
|
|
||||||
// Parse first and main IF condition
|
// Parse first and main IF condition
|
||||||
condition, err := arguments.ParseExpression()
|
condition, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if_node.conditions = append(if_node.conditions, condition)
|
ifNode.conditions = append(ifNode.conditions, condition)
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
return nil, arguments.Error("If-condition is malformed.", nil)
|
return nil, arguments.Error("If-condition is malformed.", nil)
|
||||||
|
@ -44,27 +39,27 @@ func tagIfParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error
|
||||||
|
|
||||||
// Check the rest
|
// Check the rest
|
||||||
for {
|
for {
|
||||||
wrapper, tag_args, err := doc.WrapUntilTag("elif", "else", "endif")
|
wrapper, tagArgs, err := doc.WrapUntilTag("elif", "else", "endif")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if_node.wrappers = append(if_node.wrappers, wrapper)
|
ifNode.wrappers = append(ifNode.wrappers, wrapper)
|
||||||
|
|
||||||
if wrapper.Endtag == "elif" {
|
if wrapper.Endtag == "elif" {
|
||||||
// elif can take a condition
|
// elif can take a condition
|
||||||
condition, err := tag_args.ParseExpression()
|
condition, err = tagArgs.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if_node.conditions = append(if_node.conditions, condition)
|
ifNode.conditions = append(ifNode.conditions, condition)
|
||||||
|
|
||||||
if tag_args.Remaining() > 0 {
|
if tagArgs.Remaining() > 0 {
|
||||||
return nil, tag_args.Error("Elif-condition is malformed.", nil)
|
return nil, tagArgs.Error("Elif-condition is malformed.", nil)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if tag_args.Count() > 0 {
|
if tagArgs.Count() > 0 {
|
||||||
// else/endif can't take any conditions
|
// else/endif can't take any conditions
|
||||||
return nil, tag_args.Error("Arguments not allowed here.", nil)
|
return nil, tagArgs.Error("Arguments not allowed here.", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +68,7 @@ func tagIfParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return if_node, nil
|
return ifNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
47
vendor/github.com/flosch/pongo2/tags_ifchanged.go
generated
vendored
47
vendor/github.com/flosch/pongo2/tags_ifchanged.go
generated
vendored
|
@ -5,16 +5,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type tagIfchangedNode struct {
|
type tagIfchangedNode struct {
|
||||||
watched_expr []IEvaluator
|
watchedExpr []IEvaluator
|
||||||
last_values []*Value
|
lastValues []*Value
|
||||||
last_content []byte
|
lastContent []byte
|
||||||
thenWrapper *NodeWrapper
|
thenWrapper *NodeWrapper
|
||||||
elseWrapper *NodeWrapper
|
elseWrapper *NodeWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
|
if len(node.watchedExpr) == 0 {
|
||||||
if len(node.watched_expr) == 0 {
|
|
||||||
// Check against own rendered body
|
// Check against own rendered body
|
||||||
|
|
||||||
buf := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
|
buf := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
|
||||||
|
@ -23,43 +22,43 @@ func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffe
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf_bytes := buf.Bytes()
|
bufBytes := buf.Bytes()
|
||||||
if !bytes.Equal(node.last_content, buf_bytes) {
|
if !bytes.Equal(node.lastContent, bufBytes) {
|
||||||
// Rendered content changed, output it
|
// Rendered content changed, output it
|
||||||
buffer.Write(buf_bytes)
|
writer.Write(bufBytes)
|
||||||
node.last_content = buf_bytes
|
node.lastContent = bufBytes
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
now_values := make([]*Value, 0, len(node.watched_expr))
|
nowValues := make([]*Value, 0, len(node.watchedExpr))
|
||||||
for _, expr := range node.watched_expr {
|
for _, expr := range node.watchedExpr {
|
||||||
val, err := expr.Evaluate(ctx)
|
val, err := expr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
now_values = append(now_values, val)
|
nowValues = append(nowValues, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare old to new values now
|
// Compare old to new values now
|
||||||
changed := len(node.last_values) == 0
|
changed := len(node.lastValues) == 0
|
||||||
|
|
||||||
for idx, old_val := range node.last_values {
|
for idx, oldVal := range node.lastValues {
|
||||||
if !old_val.EqualValueTo(now_values[idx]) {
|
if !oldVal.EqualValueTo(nowValues[idx]) {
|
||||||
changed = true
|
changed = true
|
||||||
break // we can stop here because ONE value changed
|
break // we can stop here because ONE value changed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.last_values = now_values
|
node.lastValues = nowValues
|
||||||
|
|
||||||
if changed {
|
if changed {
|
||||||
// Render thenWrapper
|
// Render thenWrapper
|
||||||
err := node.thenWrapper.Execute(ctx, buffer)
|
err := node.thenWrapper.Execute(ctx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Render elseWrapper
|
// Render elseWrapper
|
||||||
err := node.elseWrapper.Execute(ctx, buffer)
|
err := node.elseWrapper.Execute(ctx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -70,7 +69,7 @@ func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffe
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
ifchanged_node := &tagIfchangedNode{}
|
ifchangedNode := &tagIfchangedNode{}
|
||||||
|
|
||||||
for arguments.Remaining() > 0 {
|
for arguments.Remaining() > 0 {
|
||||||
// Parse condition
|
// Parse condition
|
||||||
|
@ -78,7 +77,7 @@ func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifchanged_node.watched_expr = append(ifchanged_node.watched_expr, expr)
|
ifchangedNode.watchedExpr = append(ifchangedNode.watchedExpr, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
|
@ -90,7 +89,7 @@ func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifchanged_node.thenWrapper = wrapper
|
ifchangedNode.thenWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
|
@ -102,14 +101,14 @@ func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifchanged_node.elseWrapper = wrapper
|
ifchangedNode.elseWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ifchanged_node, nil
|
return ifchangedNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
25
vendor/github.com/flosch/pongo2/tags_ifequal.go
generated
vendored
25
vendor/github.com/flosch/pongo2/tags_ifequal.go
generated
vendored
|
@ -1,16 +1,12 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagIfEqualNode struct {
|
type tagIfEqualNode struct {
|
||||||
var1, var2 IEvaluator
|
var1, var2 IEvaluator
|
||||||
thenWrapper *NodeWrapper
|
thenWrapper *NodeWrapper
|
||||||
elseWrapper *NodeWrapper
|
elseWrapper *NodeWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
r1, err := node.var1.Evaluate(ctx)
|
r1, err := node.var1.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -23,17 +19,16 @@ func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
||||||
result := r1.EqualValueTo(r2)
|
result := r1.EqualValueTo(r2)
|
||||||
|
|
||||||
if result {
|
if result {
|
||||||
return node.thenWrapper.Execute(ctx, buffer)
|
return node.thenWrapper.Execute(ctx, writer)
|
||||||
} else {
|
|
||||||
if node.elseWrapper != nil {
|
|
||||||
return node.elseWrapper.Execute(ctx, buffer)
|
|
||||||
}
|
}
|
||||||
|
if node.elseWrapper != nil {
|
||||||
|
return node.elseWrapper.Execute(ctx, writer)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
ifequal_node := &tagIfEqualNode{}
|
ifequalNode := &tagIfEqualNode{}
|
||||||
|
|
||||||
// Parse two expressions
|
// Parse two expressions
|
||||||
var1, err := arguments.ParseExpression()
|
var1, err := arguments.ParseExpression()
|
||||||
|
@ -44,8 +39,8 @@ func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifequal_node.var1 = var1
|
ifequalNode.var1 = var1
|
||||||
ifequal_node.var2 = var2
|
ifequalNode.var2 = var2
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
|
return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
|
||||||
|
@ -56,7 +51,7 @@ func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifequal_node.thenWrapper = wrapper
|
ifequalNode.thenWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
|
@ -68,14 +63,14 @@ func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifequal_node.elseWrapper = wrapper
|
ifequalNode.elseWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ifequal_node, nil
|
return ifequalNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
29
vendor/github.com/flosch/pongo2/tags_ifnotequal.go
generated
vendored
29
vendor/github.com/flosch/pongo2/tags_ifnotequal.go
generated
vendored
|
@ -1,16 +1,12 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagIfNotEqualNode struct {
|
type tagIfNotEqualNode struct {
|
||||||
var1, var2 IEvaluator
|
var1, var2 IEvaluator
|
||||||
thenWrapper *NodeWrapper
|
thenWrapper *NodeWrapper
|
||||||
elseWrapper *NodeWrapper
|
elseWrapper *NodeWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
r1, err := node.var1.Evaluate(ctx)
|
r1, err := node.var1.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -23,17 +19,16 @@ func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buff
|
||||||
result := !r1.EqualValueTo(r2)
|
result := !r1.EqualValueTo(r2)
|
||||||
|
|
||||||
if result {
|
if result {
|
||||||
return node.thenWrapper.Execute(ctx, buffer)
|
return node.thenWrapper.Execute(ctx, writer)
|
||||||
} else {
|
|
||||||
if node.elseWrapper != nil {
|
|
||||||
return node.elseWrapper.Execute(ctx, buffer)
|
|
||||||
}
|
}
|
||||||
|
if node.elseWrapper != nil {
|
||||||
|
return node.elseWrapper.Execute(ctx, writer)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
ifnotequal_node := &tagIfNotEqualNode{}
|
ifnotequalNode := &tagIfNotEqualNode{}
|
||||||
|
|
||||||
// Parse two expressions
|
// Parse two expressions
|
||||||
var1, err := arguments.ParseExpression()
|
var1, err := arguments.ParseExpression()
|
||||||
|
@ -44,19 +39,19 @@ func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifnotequal_node.var1 = var1
|
ifnotequalNode.var1 = var1
|
||||||
ifnotequal_node.var2 = var2
|
ifnotequalNode.var2 = var2
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
|
return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap then/else-blocks
|
// Wrap then/else-blocks
|
||||||
wrapper, endargs, err := doc.WrapUntilTag("else", "endifequal")
|
wrapper, endargs, err := doc.WrapUntilTag("else", "endifnotequal")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifnotequal_node.thenWrapper = wrapper
|
ifnotequalNode.thenWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
|
@ -64,18 +59,18 @@ func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
||||||
|
|
||||||
if wrapper.Endtag == "else" {
|
if wrapper.Endtag == "else" {
|
||||||
// if there's an else in the if-statement, we need the else-Block as well
|
// if there's an else in the if-statement, we need the else-Block as well
|
||||||
wrapper, endargs, err = doc.WrapUntilTag("endifequal")
|
wrapper, endargs, err = doc.WrapUntilTag("endifnotequal")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifnotequal_node.elseWrapper = wrapper
|
ifnotequalNode.elseWrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ifnotequal_node, nil
|
return ifnotequalNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
36
vendor/github.com/flosch/pongo2/tags_import.go
generated
vendored
36
vendor/github.com/flosch/pongo2/tags_import.go
generated
vendored
|
@ -1,18 +1,16 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tagImportNode struct {
|
type tagImportNode struct {
|
||||||
position *Token
|
position *Token
|
||||||
filename string
|
filename string
|
||||||
template *Template
|
|
||||||
macros map[string]*tagMacroNode // alias/name -> macro instance
|
macros map[string]*tagMacroNode // alias/name -> macro instance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagImportNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagImportNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
for name, macro := range node.macros {
|
for name, macro := range node.macros {
|
||||||
func(name string, macro *tagMacroNode) {
|
func(name string, macro *tagMacroNode) {
|
||||||
ctx.Private[name] = func(args ...*Value) *Value {
|
ctx.Private[name] = func(args ...*Value) *Value {
|
||||||
|
@ -24,50 +22,50 @@ func (node *tagImportNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
import_node := &tagImportNode{
|
importNode := &tagImportNode{
|
||||||
position: start,
|
position: start,
|
||||||
macros: make(map[string]*tagMacroNode),
|
macros: make(map[string]*tagMacroNode),
|
||||||
}
|
}
|
||||||
|
|
||||||
filename_token := arguments.MatchType(TokenString)
|
filenameToken := arguments.MatchType(TokenString)
|
||||||
if filename_token == nil {
|
if filenameToken == nil {
|
||||||
return nil, arguments.Error("Import-tag needs a filename as string.", nil)
|
return nil, arguments.Error("Import-tag needs a filename as string.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
import_node.filename = doc.template.set.resolveFilename(doc.template, filename_token.Val)
|
importNode.filename = doc.template.set.resolveFilename(doc.template, filenameToken.Val)
|
||||||
|
|
||||||
if arguments.Remaining() == 0 {
|
if arguments.Remaining() == 0 {
|
||||||
return nil, arguments.Error("You must at least specify one macro to import.", nil)
|
return nil, arguments.Error("You must at least specify one macro to import.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile the given template
|
// Compile the given template
|
||||||
tpl, err := doc.template.set.FromFile(import_node.filename)
|
tpl, err := doc.template.set.FromFile(importNode.filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, start)
|
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
for arguments.Remaining() > 0 {
|
for arguments.Remaining() > 0 {
|
||||||
macro_name_token := arguments.MatchType(TokenIdentifier)
|
macroNameToken := arguments.MatchType(TokenIdentifier)
|
||||||
if macro_name_token == nil {
|
if macroNameToken == nil {
|
||||||
return nil, arguments.Error("Expected macro name (identifier).", nil)
|
return nil, arguments.Error("Expected macro name (identifier).", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
as_name := macro_name_token.Val
|
asName := macroNameToken.Val
|
||||||
if arguments.Match(TokenKeyword, "as") != nil {
|
if arguments.Match(TokenKeyword, "as") != nil {
|
||||||
alias_token := arguments.MatchType(TokenIdentifier)
|
aliasToken := arguments.MatchType(TokenIdentifier)
|
||||||
if alias_token == nil {
|
if aliasToken == nil {
|
||||||
return nil, arguments.Error("Expected macro alias name (identifier).", nil)
|
return nil, arguments.Error("Expected macro alias name (identifier).", nil)
|
||||||
}
|
}
|
||||||
as_name = alias_token.Val
|
asName = aliasToken.Val
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_instance, has := tpl.exported_macros[macro_name_token.Val]
|
macroInstance, has := tpl.exportedMacros[macroNameToken.Val]
|
||||||
if !has {
|
if !has {
|
||||||
return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macro_name_token.Val,
|
return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macroNameToken.Val,
|
||||||
import_node.filename), macro_name_token)
|
importNode.filename), macroNameToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
import_node.macros[as_name] = macro_instance
|
importNode.macros[asName] = macroInstance
|
||||||
|
|
||||||
if arguments.Remaining() == 0 {
|
if arguments.Remaining() == 0 {
|
||||||
break
|
break
|
||||||
|
@ -78,7 +76,7 @@ func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return import_node, nil
|
return importNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
90
vendor/github.com/flosch/pongo2/tags_include.go
generated
vendored
90
vendor/github.com/flosch/pongo2/tags_include.go
generated
vendored
|
@ -1,41 +1,38 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagIncludeNode struct {
|
type tagIncludeNode struct {
|
||||||
tpl *Template
|
tpl *Template
|
||||||
filename_evaluator IEvaluator
|
filenameEvaluator IEvaluator
|
||||||
lazy bool
|
lazy bool
|
||||||
only bool
|
only bool
|
||||||
filename string
|
filename string
|
||||||
with_pairs map[string]IEvaluator
|
withPairs map[string]IEvaluator
|
||||||
|
ifExists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagIncludeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagIncludeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
// Building the context for the template
|
// Building the context for the template
|
||||||
include_ctx := make(Context)
|
includeCtx := make(Context)
|
||||||
|
|
||||||
// Fill the context with all data from the parent
|
// Fill the context with all data from the parent
|
||||||
if !node.only {
|
if !node.only {
|
||||||
include_ctx.Update(ctx.Public)
|
includeCtx.Update(ctx.Public)
|
||||||
include_ctx.Update(ctx.Private)
|
includeCtx.Update(ctx.Private)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put all custom with-pairs into the context
|
// Put all custom with-pairs into the context
|
||||||
for key, value := range node.with_pairs {
|
for key, value := range node.withPairs {
|
||||||
val, err := value.Evaluate(ctx)
|
val, err := value.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
include_ctx[key] = val
|
includeCtx[key] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the template
|
// Execute the template
|
||||||
if node.lazy {
|
if node.lazy {
|
||||||
// Evaluate the filename
|
// Evaluate the filename
|
||||||
filename, err := node.filename_evaluator.Evaluate(ctx)
|
filename, err := node.filenameEvaluator.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -45,76 +42,93 @@ func (node *tagIncludeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get include-filename
|
// Get include-filename
|
||||||
included_filename := ctx.template.set.resolveFilename(ctx.template, filename.String())
|
includedFilename := ctx.template.set.resolveFilename(ctx.template, filename.String())
|
||||||
|
|
||||||
included_tpl, err2 := ctx.template.set.FromFile(included_filename)
|
includedTpl, err2 := ctx.template.set.FromFile(includedFilename)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
|
// if this is ReadFile error, and "if_exists" flag is enabled
|
||||||
|
if node.ifExists && err2.(*Error).Sender == "fromfile" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err2.(*Error)
|
return err2.(*Error)
|
||||||
}
|
}
|
||||||
err2 = included_tpl.ExecuteWriter(include_ctx, buffer)
|
err2 = includedTpl.ExecuteWriter(includeCtx, writer)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
return err2.(*Error)
|
return err2.(*Error)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
} else {
|
}
|
||||||
// Template is already parsed with static filename
|
// Template is already parsed with static filename
|
||||||
err := node.tpl.ExecuteWriter(include_ctx, buffer)
|
err := node.tpl.ExecuteWriter(includeCtx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.(*Error)
|
return err.(*Error)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tagIncludeEmptyNode struct{}
|
||||||
|
|
||||||
|
func (node *tagIncludeEmptyNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagIncludeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagIncludeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
include_node := &tagIncludeNode{
|
includeNode := &tagIncludeNode{
|
||||||
with_pairs: make(map[string]IEvaluator),
|
withPairs: make(map[string]IEvaluator),
|
||||||
}
|
}
|
||||||
|
|
||||||
if filename_token := arguments.MatchType(TokenString); filename_token != nil {
|
if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
|
||||||
// prepared, static template
|
// prepared, static template
|
||||||
|
|
||||||
|
// "if_exists" flag
|
||||||
|
ifExists := arguments.Match(TokenIdentifier, "if_exists") != nil
|
||||||
|
|
||||||
// Get include-filename
|
// Get include-filename
|
||||||
included_filename := doc.template.set.resolveFilename(doc.template, filename_token.Val)
|
includedFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
|
||||||
|
|
||||||
// Parse the parent
|
// Parse the parent
|
||||||
include_node.filename = included_filename
|
includeNode.filename = includedFilename
|
||||||
included_tpl, err := doc.template.set.FromFile(included_filename)
|
includedTpl, err := doc.template.set.FromFile(includedFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, filename_token)
|
// if this is ReadFile error, and "if_exists" token presents we should create and empty node
|
||||||
|
if err.(*Error).Sender == "fromfile" && ifExists {
|
||||||
|
return &tagIncludeEmptyNode{}, nil
|
||||||
}
|
}
|
||||||
include_node.tpl = included_tpl
|
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, filenameToken)
|
||||||
|
}
|
||||||
|
includeNode.tpl = includedTpl
|
||||||
} else {
|
} else {
|
||||||
// No String, then the user wants to use lazy-evaluation (slower, but possible)
|
// No String, then the user wants to use lazy-evaluation (slower, but possible)
|
||||||
filename_evaluator, err := arguments.ParseExpression()
|
filenameEvaluator, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.updateFromTokenIfNeeded(doc.template, filename_token)
|
return nil, err.updateFromTokenIfNeeded(doc.template, filenameToken)
|
||||||
}
|
}
|
||||||
include_node.filename_evaluator = filename_evaluator
|
includeNode.filenameEvaluator = filenameEvaluator
|
||||||
include_node.lazy = true
|
includeNode.lazy = true
|
||||||
|
includeNode.ifExists = arguments.Match(TokenIdentifier, "if_exists") != nil // "if_exists" flag
|
||||||
}
|
}
|
||||||
|
|
||||||
// After having parsed the filename we're gonna parse the with+only options
|
// After having parsed the filename we're gonna parse the with+only options
|
||||||
if arguments.Match(TokenIdentifier, "with") != nil {
|
if arguments.Match(TokenIdentifier, "with") != nil {
|
||||||
for arguments.Remaining() > 0 {
|
for arguments.Remaining() > 0 {
|
||||||
// We have at least one key=expr pair (because of starting "with")
|
// We have at least one key=expr pair (because of starting "with")
|
||||||
key_token := arguments.MatchType(TokenIdentifier)
|
keyToken := arguments.MatchType(TokenIdentifier)
|
||||||
if key_token == nil {
|
if keyToken == nil {
|
||||||
return nil, arguments.Error("Expected an identifier", nil)
|
return nil, arguments.Error("Expected an identifier", nil)
|
||||||
}
|
}
|
||||||
if arguments.Match(TokenSymbol, "=") == nil {
|
if arguments.Match(TokenSymbol, "=") == nil {
|
||||||
return nil, arguments.Error("Expected '='.", nil)
|
return nil, arguments.Error("Expected '='.", nil)
|
||||||
}
|
}
|
||||||
value_expr, err := arguments.ParseExpression()
|
valueExpr, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.updateFromTokenIfNeeded(doc.template, key_token)
|
return nil, err.updateFromTokenIfNeeded(doc.template, keyToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
include_node.with_pairs[key_token.Val] = value_expr
|
includeNode.withPairs[keyToken.Val] = valueExpr
|
||||||
|
|
||||||
// Only?
|
// Only?
|
||||||
if arguments.Match(TokenIdentifier, "only") != nil {
|
if arguments.Match(TokenIdentifier, "only") != nil {
|
||||||
include_node.only = true
|
includeNode.only = true
|
||||||
break // stop parsing arguments because it's the last option
|
break // stop parsing arguments because it's the last option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +138,7 @@ func tagIncludeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
||||||
return nil, arguments.Error("Malformed 'include'-tag arguments.", nil)
|
return nil, arguments.Error("Malformed 'include'-tag arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return include_node, nil
|
return includeNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
55
vendor/github.com/flosch/pongo2/tags_lorem.go
generated
vendored
55
vendor/github.com/flosch/pongo2/tags_lorem.go
generated
vendored
|
@ -1,10 +1,11 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -19,102 +20,102 @@ type tagLoremNode struct {
|
||||||
random bool // does not use the default paragraph "Lorem ipsum dolor sit amet, ..."
|
random bool // does not use the default paragraph "Lorem ipsum dolor sit amet, ..."
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagLoremNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagLoremNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
switch node.method {
|
switch node.method {
|
||||||
case "b":
|
case "b":
|
||||||
if node.random {
|
if node.random {
|
||||||
for i := 0; i < node.count; i++ {
|
for i := 0; i < node.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer.WriteString("\n")
|
writer.WriteString("\n")
|
||||||
}
|
}
|
||||||
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
||||||
buffer.WriteString(par)
|
writer.WriteString(par)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < node.count; i++ {
|
for i := 0; i < node.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer.WriteString("\n")
|
writer.WriteString("\n")
|
||||||
}
|
}
|
||||||
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
||||||
buffer.WriteString(par)
|
writer.WriteString(par)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "w":
|
case "w":
|
||||||
if node.random {
|
if node.random {
|
||||||
for i := 0; i < node.count; i++ {
|
for i := 0; i < node.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer.WriteString(" ")
|
writer.WriteString(" ")
|
||||||
}
|
}
|
||||||
word := tagLoremWords[rand.Intn(len(tagLoremWords))]
|
word := tagLoremWords[rand.Intn(len(tagLoremWords))]
|
||||||
buffer.WriteString(word)
|
writer.WriteString(word)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < node.count; i++ {
|
for i := 0; i < node.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer.WriteString(" ")
|
writer.WriteString(" ")
|
||||||
}
|
}
|
||||||
word := tagLoremWords[i%len(tagLoremWords)]
|
word := tagLoremWords[i%len(tagLoremWords)]
|
||||||
buffer.WriteString(word)
|
writer.WriteString(word)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case "p":
|
case "p":
|
||||||
if node.random {
|
if node.random {
|
||||||
for i := 0; i < node.count; i++ {
|
for i := 0; i < node.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer.WriteString("\n")
|
writer.WriteString("\n")
|
||||||
}
|
}
|
||||||
buffer.WriteString("<p>")
|
writer.WriteString("<p>")
|
||||||
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
||||||
buffer.WriteString(par)
|
writer.WriteString(par)
|
||||||
buffer.WriteString("</p>")
|
writer.WriteString("</p>")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < node.count; i++ {
|
for i := 0; i < node.count; i++ {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
buffer.WriteString("\n")
|
writer.WriteString("\n")
|
||||||
}
|
}
|
||||||
buffer.WriteString("<p>")
|
writer.WriteString("<p>")
|
||||||
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
||||||
buffer.WriteString(par)
|
writer.WriteString(par)
|
||||||
buffer.WriteString("</p>")
|
writer.WriteString("</p>")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("unsupported method")
|
return ctx.OrigError(errors.Errorf("unsupported method: %s", node.method), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagLoremParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagLoremParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
lorem_node := &tagLoremNode{
|
loremNode := &tagLoremNode{
|
||||||
position: start,
|
position: start,
|
||||||
count: 1,
|
count: 1,
|
||||||
method: "b",
|
method: "b",
|
||||||
}
|
}
|
||||||
|
|
||||||
if count_token := arguments.MatchType(TokenNumber); count_token != nil {
|
if countToken := arguments.MatchType(TokenNumber); countToken != nil {
|
||||||
lorem_node.count = AsValue(count_token.Val).Integer()
|
loremNode.count = AsValue(countToken.Val).Integer()
|
||||||
}
|
}
|
||||||
|
|
||||||
if method_token := arguments.MatchType(TokenIdentifier); method_token != nil {
|
if methodToken := arguments.MatchType(TokenIdentifier); methodToken != nil {
|
||||||
if method_token.Val != "w" && method_token.Val != "p" && method_token.Val != "b" {
|
if methodToken.Val != "w" && methodToken.Val != "p" && methodToken.Val != "b" {
|
||||||
return nil, arguments.Error("lorem-method must be either 'w', 'p' or 'b'.", nil)
|
return nil, arguments.Error("lorem-method must be either 'w', 'p' or 'b'.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
lorem_node.method = method_token.Val
|
loremNode.method = methodToken.Val
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.MatchOne(TokenIdentifier, "random") != nil {
|
if arguments.MatchOne(TokenIdentifier, "random") != nil {
|
||||||
lorem_node.random = true
|
loremNode.random = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
return nil, arguments.Error("Malformed lorem-tag arguments.", nil)
|
return nil, arguments.Error("Malformed lorem-tag arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return lorem_node, nil
|
return loremNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
56
vendor/github.com/flosch/pongo2/tags_macro.go
generated
vendored
56
vendor/github.com/flosch/pongo2/tags_macro.go
generated
vendored
|
@ -8,14 +8,14 @@ import (
|
||||||
type tagMacroNode struct {
|
type tagMacroNode struct {
|
||||||
position *Token
|
position *Token
|
||||||
name string
|
name string
|
||||||
args_order []string
|
argsOrder []string
|
||||||
args map[string]IEvaluator
|
args map[string]IEvaluator
|
||||||
exported bool
|
exported bool
|
||||||
|
|
||||||
wrapper *NodeWrapper
|
wrapper *NodeWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagMacroNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagMacroNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
ctx.Private[node.name] = func(args ...*Value) *Value {
|
ctx.Private[node.name] = func(args ...*Value) *Value {
|
||||||
return node.call(ctx, args...)
|
return node.call(ctx, args...)
|
||||||
}
|
}
|
||||||
|
@ -24,28 +24,28 @@ func (node *tagMacroNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagMacroNode) call(ctx *ExecutionContext, args ...*Value) *Value {
|
func (node *tagMacroNode) call(ctx *ExecutionContext, args ...*Value) *Value {
|
||||||
args_ctx := make(Context)
|
argsCtx := make(Context)
|
||||||
|
|
||||||
for k, v := range node.args {
|
for k, v := range node.args {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
// User did not provided a default value
|
// User did not provided a default value
|
||||||
args_ctx[k] = nil
|
argsCtx[k] = nil
|
||||||
} else {
|
} else {
|
||||||
// Evaluate the default value
|
// Evaluate the default value
|
||||||
value_expr, err := v.Evaluate(ctx)
|
valueExpr, err := v.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Logf(err.Error())
|
ctx.Logf(err.Error())
|
||||||
return AsSafeValue(err.Error())
|
return AsSafeValue(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
args_ctx[k] = value_expr
|
argsCtx[k] = valueExpr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args) > len(node.args_order) {
|
if len(args) > len(node.argsOrder) {
|
||||||
// Too many arguments, we're ignoring them and just logging into debug mode.
|
// Too many arguments, we're ignoring them and just logging into debug mode.
|
||||||
err := ctx.Error(fmt.Sprintf("Macro '%s' called with too many arguments (%d instead of %d).",
|
err := ctx.Error(fmt.Sprintf("Macro '%s' called with too many arguments (%d instead of %d).",
|
||||||
node.name, len(args), len(node.args_order)), nil).updateFromTokenIfNeeded(ctx.template, node.position)
|
node.name, len(args), len(node.argsOrder)), nil).updateFromTokenIfNeeded(ctx.template, node.position)
|
||||||
|
|
||||||
ctx.Logf(err.Error()) // TODO: This is a workaround, because the error is not returned yet to the Execution()-methods
|
ctx.Logf(err.Error()) // TODO: This is a workaround, because the error is not returned yet to the Execution()-methods
|
||||||
return AsSafeValue(err.Error())
|
return AsSafeValue(err.Error())
|
||||||
|
@ -55,10 +55,10 @@ func (node *tagMacroNode) call(ctx *ExecutionContext, args ...*Value) *Value {
|
||||||
macroCtx := NewChildExecutionContext(ctx)
|
macroCtx := NewChildExecutionContext(ctx)
|
||||||
|
|
||||||
// Register all arguments in the private context
|
// Register all arguments in the private context
|
||||||
macroCtx.Private.Update(args_ctx)
|
macroCtx.Private.Update(argsCtx)
|
||||||
|
|
||||||
for idx, arg_value := range args {
|
for idx, argValue := range args {
|
||||||
macroCtx.Private[node.args_order[idx]] = arg_value.Interface()
|
macroCtx.Private[node.argsOrder[idx]] = argValue.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
@ -71,38 +71,38 @@ func (node *tagMacroNode) call(ctx *ExecutionContext, args ...*Value) *Value {
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
macro_node := &tagMacroNode{
|
macroNode := &tagMacroNode{
|
||||||
position: start,
|
position: start,
|
||||||
args: make(map[string]IEvaluator),
|
args: make(map[string]IEvaluator),
|
||||||
}
|
}
|
||||||
|
|
||||||
name_token := arguments.MatchType(TokenIdentifier)
|
nameToken := arguments.MatchType(TokenIdentifier)
|
||||||
if name_token == nil {
|
if nameToken == nil {
|
||||||
return nil, arguments.Error("Macro-tag needs at least an identifier as name.", nil)
|
return nil, arguments.Error("Macro-tag needs at least an identifier as name.", nil)
|
||||||
}
|
}
|
||||||
macro_node.name = name_token.Val
|
macroNode.name = nameToken.Val
|
||||||
|
|
||||||
if arguments.MatchOne(TokenSymbol, "(") == nil {
|
if arguments.MatchOne(TokenSymbol, "(") == nil {
|
||||||
return nil, arguments.Error("Expected '('.", nil)
|
return nil, arguments.Error("Expected '('.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
for arguments.Match(TokenSymbol, ")") == nil {
|
for arguments.Match(TokenSymbol, ")") == nil {
|
||||||
arg_name_token := arguments.MatchType(TokenIdentifier)
|
argNameToken := arguments.MatchType(TokenIdentifier)
|
||||||
if arg_name_token == nil {
|
if argNameToken == nil {
|
||||||
return nil, arguments.Error("Expected argument name as identifier.", nil)
|
return nil, arguments.Error("Expected argument name as identifier.", nil)
|
||||||
}
|
}
|
||||||
macro_node.args_order = append(macro_node.args_order, arg_name_token.Val)
|
macroNode.argsOrder = append(macroNode.argsOrder, argNameToken.Val)
|
||||||
|
|
||||||
if arguments.Match(TokenSymbol, "=") != nil {
|
if arguments.Match(TokenSymbol, "=") != nil {
|
||||||
// Default expression follows
|
// Default expression follows
|
||||||
arg_default_expr, err := arguments.ParseExpression()
|
argDefaultExpr, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
macro_node.args[arg_name_token.Val] = arg_default_expr
|
macroNode.args[argNameToken.Val] = argDefaultExpr
|
||||||
} else {
|
} else {
|
||||||
// No default expression
|
// No default expression
|
||||||
macro_node.args[arg_name_token.Val] = nil
|
macroNode.args[argNameToken.Val] = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Match(TokenSymbol, ")") != nil {
|
if arguments.Match(TokenSymbol, ")") != nil {
|
||||||
|
@ -114,7 +114,7 @@ func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Match(TokenKeyword, "export") != nil {
|
if arguments.Match(TokenKeyword, "export") != nil {
|
||||||
macro_node.exported = true
|
macroNode.exported = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
|
@ -126,22 +126,22 @@ func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
macro_node.wrapper = wrapper
|
macroNode.wrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if macro_node.exported {
|
if macroNode.exported {
|
||||||
// Now register the macro if it wants to be exported
|
// Now register the macro if it wants to be exported
|
||||||
_, has := doc.template.exported_macros[macro_node.name]
|
_, has := doc.template.exportedMacros[macroNode.name]
|
||||||
if has {
|
if has {
|
||||||
return nil, doc.Error(fmt.Sprintf("Another macro with name '%s' already exported.", macro_node.name), start)
|
return nil, doc.Error(fmt.Sprintf("another macro with name '%s' already exported", macroNode.name), start)
|
||||||
}
|
}
|
||||||
doc.template.exported_macros[macro_node.name] = macro_node
|
doc.template.exportedMacros[macroNode.name] = macroNode
|
||||||
}
|
}
|
||||||
|
|
||||||
return macro_node, nil
|
return macroNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
17
vendor/github.com/flosch/pongo2/tags_now.go
generated
vendored
17
vendor/github.com/flosch/pongo2/tags_now.go
generated
vendored
|
@ -1,7 +1,6 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ type tagNowNode struct {
|
||||||
fake bool
|
fake bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagNowNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagNowNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
var t time.Time
|
var t time.Time
|
||||||
if node.fake {
|
if node.fake {
|
||||||
t = time.Date(2014, time.February, 05, 18, 31, 45, 00, time.UTC)
|
t = time.Date(2014, time.February, 05, 18, 31, 45, 00, time.UTC)
|
||||||
|
@ -19,31 +18,31 @@ func (node *tagNowNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Er
|
||||||
t = time.Now()
|
t = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(t.Format(node.format))
|
writer.WriteString(t.Format(node.format))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagNowParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagNowParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
now_node := &tagNowNode{
|
nowNode := &tagNowNode{
|
||||||
position: start,
|
position: start,
|
||||||
}
|
}
|
||||||
|
|
||||||
format_token := arguments.MatchType(TokenString)
|
formatToken := arguments.MatchType(TokenString)
|
||||||
if format_token == nil {
|
if formatToken == nil {
|
||||||
return nil, arguments.Error("Expected a format string.", nil)
|
return nil, arguments.Error("Expected a format string.", nil)
|
||||||
}
|
}
|
||||||
now_node.format = format_token.Val
|
nowNode.format = formatToken.Val
|
||||||
|
|
||||||
if arguments.MatchOne(TokenIdentifier, "fake") != nil {
|
if arguments.MatchOne(TokenIdentifier, "fake") != nil {
|
||||||
now_node.fake = true
|
nowNode.fake = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
return nil, arguments.Error("Malformed now-tag arguments.", nil)
|
return nil, arguments.Error("Malformed now-tag arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return now_node, nil
|
return nowNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
4
vendor/github.com/flosch/pongo2/tags_set.go
generated
vendored
4
vendor/github.com/flosch/pongo2/tags_set.go
generated
vendored
|
@ -1,13 +1,11 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import "bytes"
|
|
||||||
|
|
||||||
type tagSetNode struct {
|
type tagSetNode struct {
|
||||||
name string
|
name string
|
||||||
expression IEvaluator
|
expression IEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagSetNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagSetNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
// Evaluate expression
|
// Evaluate expression
|
||||||
value, err := node.expression.Evaluate(ctx)
|
value, err := node.expression.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
10
vendor/github.com/flosch/pongo2/tags_spaceless.go
generated
vendored
10
vendor/github.com/flosch/pongo2/tags_spaceless.go
generated
vendored
|
@ -11,7 +11,7 @@ type tagSpacelessNode struct {
|
||||||
|
|
||||||
var tagSpacelessRegexp = regexp.MustCompile(`(?U:(<.*>))([\t\n\v\f\r ]+)(?U:(<.*>))`)
|
var tagSpacelessRegexp = regexp.MustCompile(`(?U:(<.*>))([\t\n\v\f\r ]+)(?U:(<.*>))`)
|
||||||
|
|
||||||
func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
b := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
|
b := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
|
||||||
|
|
||||||
err := node.wrapper.Execute(ctx, b)
|
err := node.wrapper.Execute(ctx, b)
|
||||||
|
@ -28,25 +28,25 @@ func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffe
|
||||||
s = s2
|
s = s2
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(s)
|
writer.WriteString(s)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagSpacelessParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagSpacelessParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
spaceless_node := &tagSpacelessNode{}
|
spacelessNode := &tagSpacelessNode{}
|
||||||
|
|
||||||
wrapper, _, err := doc.WrapUntilTag("endspaceless")
|
wrapper, _, err := doc.WrapUntilTag("endspaceless")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
spaceless_node.wrapper = wrapper
|
spacelessNode.wrapper = wrapper
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
return nil, arguments.Error("Malformed spaceless-tag arguments.", nil)
|
return nil, arguments.Error("Malformed spaceless-tag arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return spaceless_node, nil
|
return spacelessNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
29
vendor/github.com/flosch/pongo2/tags_ssi.go
generated
vendored
29
vendor/github.com/flosch/pongo2/tags_ssi.go
generated
vendored
|
@ -1,7 +1,6 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -11,47 +10,47 @@ type tagSSINode struct {
|
||||||
template *Template
|
template *Template
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagSSINode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagSSINode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
if node.template != nil {
|
if node.template != nil {
|
||||||
// Execute the template within the current context
|
// Execute the template within the current context
|
||||||
includeCtx := make(Context)
|
includeCtx := make(Context)
|
||||||
includeCtx.Update(ctx.Public)
|
includeCtx.Update(ctx.Public)
|
||||||
includeCtx.Update(ctx.Private)
|
includeCtx.Update(ctx.Private)
|
||||||
|
|
||||||
err := node.template.ExecuteWriter(includeCtx, buffer)
|
err := node.template.execute(includeCtx, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.(*Error)
|
return err.(*Error)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Just print out the content
|
// Just print out the content
|
||||||
buffer.WriteString(node.content)
|
writer.WriteString(node.content)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagSSIParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagSSIParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
ssi_node := &tagSSINode{}
|
SSINode := &tagSSINode{}
|
||||||
|
|
||||||
if file_token := arguments.MatchType(TokenString); file_token != nil {
|
if fileToken := arguments.MatchType(TokenString); fileToken != nil {
|
||||||
ssi_node.filename = file_token.Val
|
SSINode.filename = fileToken.Val
|
||||||
|
|
||||||
if arguments.Match(TokenIdentifier, "parsed") != nil {
|
if arguments.Match(TokenIdentifier, "parsed") != nil {
|
||||||
// parsed
|
// parsed
|
||||||
temporary_tpl, err := doc.template.set.FromFile(doc.template.set.resolveFilename(doc.template, file_token.Val))
|
temporaryTpl, err := doc.template.set.FromFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, file_token)
|
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, fileToken)
|
||||||
}
|
}
|
||||||
ssi_node.template = temporary_tpl
|
SSINode.template = temporaryTpl
|
||||||
} else {
|
} else {
|
||||||
// plaintext
|
// plaintext
|
||||||
buf, err := ioutil.ReadFile(doc.template.set.resolveFilename(doc.template, file_token.Val))
|
buf, err := ioutil.ReadFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, (&Error{
|
return nil, (&Error{
|
||||||
Sender: "tag:ssi",
|
Sender: "tag:ssi",
|
||||||
ErrorMsg: err.Error(),
|
OrigError: err,
|
||||||
}).updateFromTokenIfNeeded(doc.template, file_token)
|
}).updateFromTokenIfNeeded(doc.template, fileToken)
|
||||||
}
|
}
|
||||||
ssi_node.content = string(buf)
|
SSINode.content = string(buf)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, arguments.Error("First argument must be a string.", nil)
|
return nil, arguments.Error("First argument must be a string.", nil)
|
||||||
|
@ -61,7 +60,7 @@ func tagSSIParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Erro
|
||||||
return nil, arguments.Error("Malformed SSI-tag argument.", nil)
|
return nil, arguments.Error("Malformed SSI-tag argument.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ssi_node, nil
|
return SSINode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
20
vendor/github.com/flosch/pongo2/tags_templatetag.go
generated
vendored
20
vendor/github.com/flosch/pongo2/tags_templatetag.go
generated
vendored
|
@ -1,9 +1,5 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagTemplateTagNode struct {
|
type tagTemplateTagNode struct {
|
||||||
content string
|
content string
|
||||||
}
|
}
|
||||||
|
@ -19,20 +15,20 @@ var templateTagMapping = map[string]string{
|
||||||
"closecomment": "#}",
|
"closecomment": "#}",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
buffer.WriteString(node.content)
|
writer.WriteString(node.content)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
tt_node := &tagTemplateTagNode{}
|
ttNode := &tagTemplateTagNode{}
|
||||||
|
|
||||||
if arg_token := arguments.MatchType(TokenIdentifier); arg_token != nil {
|
if argToken := arguments.MatchType(TokenIdentifier); argToken != nil {
|
||||||
output, found := templateTagMapping[arg_token.Val]
|
output, found := templateTagMapping[argToken.Val]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, arguments.Error("Argument not found", arg_token)
|
return nil, arguments.Error("Argument not found", argToken)
|
||||||
}
|
}
|
||||||
tt_node.content = output
|
ttNode.content = output
|
||||||
} else {
|
} else {
|
||||||
return nil, arguments.Error("Identifier expected.", nil)
|
return nil, arguments.Error("Identifier expected.", nil)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +37,7 @@ func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTa
|
||||||
return nil, arguments.Error("Malformed templatetag-tag argument.", nil)
|
return nil, arguments.Error("Malformed templatetag-tag argument.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return tt_node, nil
|
return ttNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
27
vendor/github.com/flosch/pongo2/tags_widthratio.go
generated
vendored
27
vendor/github.com/flosch/pongo2/tags_widthratio.go
generated
vendored
|
@ -1,7 +1,6 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
@ -10,10 +9,10 @@ type tagWidthratioNode struct {
|
||||||
position *Token
|
position *Token
|
||||||
current, max IEvaluator
|
current, max IEvaluator
|
||||||
width IEvaluator
|
width IEvaluator
|
||||||
ctx_name string
|
ctxName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
current, err := node.current.Evaluate(ctx)
|
current, err := node.current.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,17 +30,17 @@ func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, buffer *bytes.Buff
|
||||||
|
|
||||||
value := int(math.Ceil(current.Float()/max.Float()*width.Float() + 0.5))
|
value := int(math.Ceil(current.Float()/max.Float()*width.Float() + 0.5))
|
||||||
|
|
||||||
if node.ctx_name == "" {
|
if node.ctxName == "" {
|
||||||
buffer.WriteString(fmt.Sprintf("%d", value))
|
writer.WriteString(fmt.Sprintf("%d", value))
|
||||||
} else {
|
} else {
|
||||||
ctx.Private[node.ctx_name] = value
|
ctx.Private[node.ctxName] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
widthratio_node := &tagWidthratioNode{
|
widthratioNode := &tagWidthratioNode{
|
||||||
position: start,
|
position: start,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,34 +48,34 @@ func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
widthratio_node.current = current
|
widthratioNode.current = current
|
||||||
|
|
||||||
max, err := arguments.ParseExpression()
|
max, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
widthratio_node.max = max
|
widthratioNode.max = max
|
||||||
|
|
||||||
width, err := arguments.ParseExpression()
|
width, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
widthratio_node.width = width
|
widthratioNode.width = width
|
||||||
|
|
||||||
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
||||||
// Name follows
|
// Name follows
|
||||||
name_token := arguments.MatchType(TokenIdentifier)
|
nameToken := arguments.MatchType(TokenIdentifier)
|
||||||
if name_token == nil {
|
if nameToken == nil {
|
||||||
return nil, arguments.Error("Expected name (identifier).", nil)
|
return nil, arguments.Error("Expected name (identifier).", nil)
|
||||||
}
|
}
|
||||||
widthratio_node.ctx_name = name_token.Val
|
widthratioNode.ctxName = nameToken.Val
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Remaining() > 0 {
|
if arguments.Remaining() > 0 {
|
||||||
return nil, arguments.Error("Malformed widthratio-tag arguments.", nil)
|
return nil, arguments.Error("Malformed widthratio-tag arguments.", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return widthratio_node, nil
|
return widthratioNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
42
vendor/github.com/flosch/pongo2/tags_with.go
generated
vendored
42
vendor/github.com/flosch/pongo2/tags_with.go
generated
vendored
|
@ -1,20 +1,16 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
)
|
|
||||||
|
|
||||||
type tagWithNode struct {
|
type tagWithNode struct {
|
||||||
with_pairs map[string]IEvaluator
|
withPairs map[string]IEvaluator
|
||||||
wrapper *NodeWrapper
|
wrapper *NodeWrapper
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *tagWithNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (node *tagWithNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
//new context for block
|
//new context for block
|
||||||
withctx := NewChildExecutionContext(ctx)
|
withctx := NewChildExecutionContext(ctx)
|
||||||
|
|
||||||
// Put all custom with-pairs into the context
|
// Put all custom with-pairs into the context
|
||||||
for key, value := range node.with_pairs {
|
for key, value := range node.withPairs {
|
||||||
val, err := value.Evaluate(ctx)
|
val, err := value.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -22,12 +18,12 @@ func (node *tagWithNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *E
|
||||||
withctx.Private[key] = val
|
withctx.Private[key] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
return node.wrapper.Execute(withctx, buffer)
|
return node.wrapper.Execute(withctx, writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tagWithParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
func tagWithParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||||
with_node := &tagWithNode{
|
withNode := &tagWithNode{
|
||||||
with_pairs: make(map[string]IEvaluator),
|
withPairs: make(map[string]IEvaluator),
|
||||||
}
|
}
|
||||||
|
|
||||||
if arguments.Count() == 0 {
|
if arguments.Count() == 0 {
|
||||||
|
@ -38,7 +34,7 @@ func tagWithParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Err
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
with_node.wrapper = wrapper
|
withNode.wrapper = wrapper
|
||||||
|
|
||||||
if endargs.Count() > 0 {
|
if endargs.Count() > 0 {
|
||||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||||
|
@ -46,45 +42,45 @@ func tagWithParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Err
|
||||||
|
|
||||||
// Scan through all arguments to see which style the user uses (old or new style).
|
// Scan through all arguments to see which style the user uses (old or new style).
|
||||||
// If we find any "as" keyword we will enforce old style; otherwise we will use new style.
|
// If we find any "as" keyword we will enforce old style; otherwise we will use new style.
|
||||||
old_style := false // by default we're using the new_style
|
oldStyle := false // by default we're using the new_style
|
||||||
for i := 0; i < arguments.Count(); i++ {
|
for i := 0; i < arguments.Count(); i++ {
|
||||||
if arguments.PeekN(i, TokenKeyword, "as") != nil {
|
if arguments.PeekN(i, TokenKeyword, "as") != nil {
|
||||||
old_style = true
|
oldStyle = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for arguments.Remaining() > 0 {
|
for arguments.Remaining() > 0 {
|
||||||
if old_style {
|
if oldStyle {
|
||||||
value_expr, err := arguments.ParseExpression()
|
valueExpr, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if arguments.Match(TokenKeyword, "as") == nil {
|
if arguments.Match(TokenKeyword, "as") == nil {
|
||||||
return nil, arguments.Error("Expected 'as' keyword.", nil)
|
return nil, arguments.Error("Expected 'as' keyword.", nil)
|
||||||
}
|
}
|
||||||
key_token := arguments.MatchType(TokenIdentifier)
|
keyToken := arguments.MatchType(TokenIdentifier)
|
||||||
if key_token == nil {
|
if keyToken == nil {
|
||||||
return nil, arguments.Error("Expected an identifier", nil)
|
return nil, arguments.Error("Expected an identifier", nil)
|
||||||
}
|
}
|
||||||
with_node.with_pairs[key_token.Val] = value_expr
|
withNode.withPairs[keyToken.Val] = valueExpr
|
||||||
} else {
|
} else {
|
||||||
key_token := arguments.MatchType(TokenIdentifier)
|
keyToken := arguments.MatchType(TokenIdentifier)
|
||||||
if key_token == nil {
|
if keyToken == nil {
|
||||||
return nil, arguments.Error("Expected an identifier", nil)
|
return nil, arguments.Error("Expected an identifier", nil)
|
||||||
}
|
}
|
||||||
if arguments.Match(TokenSymbol, "=") == nil {
|
if arguments.Match(TokenSymbol, "=") == nil {
|
||||||
return nil, arguments.Error("Expected '='.", nil)
|
return nil, arguments.Error("Expected '='.", nil)
|
||||||
}
|
}
|
||||||
value_expr, err := arguments.ParseExpression()
|
valueExpr, err := arguments.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
with_node.with_pairs[key_token.Val] = value_expr
|
withNode.withPairs[keyToken.Val] = valueExpr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return with_node, nil
|
return withNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
104
vendor/github.com/flosch/pongo2/template.go
generated
vendored
104
vendor/github.com/flosch/pongo2/template.go
generated
vendored
|
@ -2,15 +2,33 @@ package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TemplateWriter interface {
|
||||||
|
io.Writer
|
||||||
|
WriteString(string) (int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type templateWriter struct {
|
||||||
|
w io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tw *templateWriter) WriteString(s string) (int, error) {
|
||||||
|
return tw.w.Write([]byte(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tw *templateWriter) Write(b []byte) (int, error) {
|
||||||
|
return tw.w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
type Template struct {
|
type Template struct {
|
||||||
set *TemplateSet
|
set *TemplateSet
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
is_tpl_string bool
|
isTplString bool
|
||||||
name string
|
name string
|
||||||
tpl string
|
tpl string
|
||||||
size int
|
size int
|
||||||
|
@ -24,30 +42,32 @@ type Template struct {
|
||||||
parent *Template
|
parent *Template
|
||||||
child *Template
|
child *Template
|
||||||
blocks map[string]*NodeWrapper
|
blocks map[string]*NodeWrapper
|
||||||
exported_macros map[string]*tagMacroNode
|
exportedMacros map[string]*tagMacroNode
|
||||||
|
|
||||||
// Output
|
// Output
|
||||||
root *nodeDocument
|
root *nodeDocument
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTemplateString(set *TemplateSet, tpl string) (*Template, error) {
|
func newTemplateString(set *TemplateSet, tpl []byte) (*Template, error) {
|
||||||
return newTemplate(set, "<string>", true, tpl)
|
return newTemplate(set, "<string>", true, tpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTemplate(set *TemplateSet, name string, is_tpl_string bool, tpl string) (*Template, error) {
|
func newTemplate(set *TemplateSet, name string, isTplString bool, tpl []byte) (*Template, error) {
|
||||||
|
strTpl := string(tpl)
|
||||||
|
|
||||||
// Create the template
|
// Create the template
|
||||||
t := &Template{
|
t := &Template{
|
||||||
set: set,
|
set: set,
|
||||||
is_tpl_string: is_tpl_string,
|
isTplString: isTplString,
|
||||||
name: name,
|
name: name,
|
||||||
tpl: tpl,
|
tpl: strTpl,
|
||||||
size: len(tpl),
|
size: len(strTpl),
|
||||||
blocks: make(map[string]*NodeWrapper),
|
blocks: make(map[string]*NodeWrapper),
|
||||||
exported_macros: make(map[string]*tagMacroNode),
|
exportedMacros: make(map[string]*tagMacroNode),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tokenize it
|
// Tokenize it
|
||||||
tokens, err := lex(name, tpl)
|
tokens, err := lex(name, strTpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -67,11 +87,7 @@ func newTemplate(set *TemplateSet, name string, is_tpl_string bool, tpl string)
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tpl *Template) execute(context Context) (*bytes.Buffer, error) {
|
func (tpl *Template) execute(context Context, writer TemplateWriter) error {
|
||||||
// Create output buffer
|
|
||||||
// We assume that the rendered template will be 30% larger
|
|
||||||
buffer := bytes.NewBuffer(make([]byte, 0, int(float64(tpl.size)*1.3)))
|
|
||||||
|
|
||||||
// Determine the parent to be executed (for template inheritance)
|
// Determine the parent to be executed (for template inheritance)
|
||||||
parent := tpl
|
parent := tpl
|
||||||
for parent.parent != nil {
|
for parent.parent != nil {
|
||||||
|
@ -89,17 +105,17 @@ func (tpl *Template) execute(context Context) (*bytes.Buffer, error) {
|
||||||
// Check for context name syntax
|
// Check for context name syntax
|
||||||
err := newContext.checkForValidIdentifiers()
|
err := newContext.checkForValidIdentifiers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for clashes with macro names
|
// Check for clashes with macro names
|
||||||
for k, _ := range newContext {
|
for k := range newContext {
|
||||||
_, has := tpl.exported_macros[k]
|
_, has := tpl.exportedMacros[k]
|
||||||
if has {
|
if has {
|
||||||
return nil, &Error{
|
return &Error{
|
||||||
Filename: tpl.name,
|
Filename: tpl.name,
|
||||||
Sender: "execution",
|
Sender: "execution",
|
||||||
ErrorMsg: fmt.Sprintf("Context key name '%s' clashes with macro '%s'.", k, k),
|
OrigError: errors.Errorf("context key name '%s' clashes with macro '%s'", k, k),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,8 +126,22 @@ func (tpl *Template) execute(context Context) (*bytes.Buffer, error) {
|
||||||
ctx := newExecutionContext(parent, newContext)
|
ctx := newExecutionContext(parent, newContext)
|
||||||
|
|
||||||
// Run the selected document
|
// Run the selected document
|
||||||
err := parent.root.Execute(ctx, buffer)
|
if err := parent.root.Execute(ctx, writer); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tpl *Template) newTemplateWriterAndExecute(context Context, writer io.Writer) error {
|
||||||
|
return tpl.execute(context, &templateWriter{w: writer})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tpl *Template) newBufferAndExecute(context Context) (*bytes.Buffer, error) {
|
||||||
|
// Create output buffer
|
||||||
|
// We assume that the rendered template will be 30% larger
|
||||||
|
buffer := bytes.NewBuffer(make([]byte, 0, int(float64(tpl.size)*1.3)))
|
||||||
|
if err := tpl.execute(context, buffer); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return buffer, nil
|
return buffer, nil
|
||||||
|
@ -121,30 +151,30 @@ func (tpl *Template) execute(context Context) (*bytes.Buffer, error) {
|
||||||
// on success. Context can be nil. Nothing is written on error; instead the error
|
// on success. Context can be nil. Nothing is written on error; instead the error
|
||||||
// is being returned.
|
// is being returned.
|
||||||
func (tpl *Template) ExecuteWriter(context Context, writer io.Writer) error {
|
func (tpl *Template) ExecuteWriter(context Context, writer io.Writer) error {
|
||||||
buffer, err := tpl.execute(context)
|
buf, err := tpl.newBufferAndExecute(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, err = buf.WriteTo(writer)
|
||||||
l := buffer.Len()
|
if err != nil {
|
||||||
n, werr := buffer.WriteTo(writer)
|
return err
|
||||||
if int(n) != l {
|
|
||||||
panic(fmt.Sprintf("error on writing template: n(%d) != buffer.Len(%d)", n, l))
|
|
||||||
}
|
|
||||||
if werr != nil {
|
|
||||||
return &Error{
|
|
||||||
Filename: tpl.name,
|
|
||||||
Sender: "execution",
|
|
||||||
ErrorMsg: werr.Error(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Same as ExecuteWriter. The only difference between both functions is that
|
||||||
|
// this function might already have written parts of the generated template in the
|
||||||
|
// case of an execution error because there's no intermediate buffer involved for
|
||||||
|
// performance reasons. This is handy if you need high performance template
|
||||||
|
// generation or if you want to manage your own pool of buffers.
|
||||||
|
func (tpl *Template) ExecuteWriterUnbuffered(context Context, writer io.Writer) error {
|
||||||
|
return tpl.newTemplateWriterAndExecute(context, writer)
|
||||||
|
}
|
||||||
|
|
||||||
// Executes the template and returns the rendered template as a []byte
|
// Executes the template and returns the rendered template as a []byte
|
||||||
func (tpl *Template) ExecuteBytes(context Context) ([]byte, error) {
|
func (tpl *Template) ExecuteBytes(context Context) ([]byte, error) {
|
||||||
// Execute template
|
// Execute template
|
||||||
buffer, err := tpl.execute(context)
|
buffer, err := tpl.newBufferAndExecute(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -154,7 +184,7 @@ func (tpl *Template) ExecuteBytes(context Context) ([]byte, error) {
|
||||||
// Executes the template and returns the rendered template as a string
|
// Executes the template and returns the rendered template as a string
|
||||||
func (tpl *Template) Execute(context Context) (string, error) {
|
func (tpl *Template) Execute(context Context) (string, error) {
|
||||||
// Execute template
|
// Execute template
|
||||||
buffer, err := tpl.execute(context)
|
buffer, err := tpl.newBufferAndExecute(context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
157
vendor/github.com/flosch/pongo2/template_loader.go
generated
vendored
Normal file
157
vendor/github.com/flosch/pongo2/template_loader.go
generated
vendored
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
package pongo2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 errors.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 = ""
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
*/
|
250
vendor/github.com/flosch/pongo2/template_sets.go
generated
vendored
250
vendor/github.com/flosch/pongo2/template_sets.go
generated
vendored
|
@ -2,48 +2,49 @@ package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A template set allows you to create your own group of templates with their own global context (which is shared
|
// TemplateLoader allows to implement a virtual file system.
|
||||||
// among all members of the set), their own configuration (like a specific base directory) and their own sandbox.
|
type TemplateLoader interface {
|
||||||
// It's useful for a separation of different kind of templates (e. g. web templates vs. mail templates).
|
// Abs calculates the path to a given template. Whenever a path must be resolved
|
||||||
|
// due to an import from another template, the base equals the parent template's path.
|
||||||
|
Abs(base, name string) string
|
||||||
|
|
||||||
|
// Get returns an io.Reader where the template's content can be read from.
|
||||||
|
Get(path string) (io.Reader, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TemplateSet allows you to create your own group of templates with their own
|
||||||
|
// global context (which is shared among all members of the set) and their own
|
||||||
|
// configuration.
|
||||||
|
// It's useful for a separation of different kind of templates
|
||||||
|
// (e. g. web templates vs. mail templates).
|
||||||
type TemplateSet struct {
|
type TemplateSet struct {
|
||||||
name string
|
name string
|
||||||
|
loader TemplateLoader
|
||||||
|
|
||||||
// Globals will be provided to all templates created within this template set
|
// Globals will be provided to all templates created within this template set
|
||||||
Globals Context
|
Globals Context
|
||||||
|
|
||||||
// If debug is true (default false), ExecutionContext.Logf() will work and output to STDOUT. Furthermore,
|
// If debug is true (default false), ExecutionContext.Logf() will work and output
|
||||||
// FromCache() won't cache the templates. Make sure to synchronize the access to it in case you're changing this
|
// to STDOUT. Furthermore, FromCache() won't cache the templates.
|
||||||
|
// Make sure to synchronize the access to it in case you're changing this
|
||||||
// variable during program execution (and template compilation/execution).
|
// variable during program execution (and template compilation/execution).
|
||||||
Debug bool
|
Debug bool
|
||||||
|
|
||||||
// Base directory: If you set the base directory (string is non-empty), all filename lookups in tags/filters are
|
|
||||||
// relative to this directory. If it's empty, all lookups are relative to the current filename which is importing.
|
|
||||||
baseDirectory string
|
|
||||||
|
|
||||||
// Sandbox features
|
// Sandbox features
|
||||||
// - Limit access to directories (using SandboxDirectories)
|
|
||||||
// - Disallow access to specific tags and/or filters (using BanTag() and BanFilter())
|
// - Disallow access to specific tags and/or filters (using BanTag() and BanFilter())
|
||||||
//
|
//
|
||||||
// You can limit file accesses (for all tags/filters which are using pongo2's file resolver technique)
|
// For efficiency reasons you can ban tags/filters only *before* you have
|
||||||
// to these sandbox directories. All default pongo2 filters/tags are respecting these restrictions.
|
// added your first template to the set (restrictions are statically checked).
|
||||||
// For example, if you only have your base directory in the list, a {% ssi "/etc/passwd" %} will not work.
|
// After you added one, it's not possible anymore (for your personal security).
|
||||||
// No items in SandboxDirectories means no restrictions at all.
|
|
||||||
//
|
|
||||||
// For efficiency reasons you can ban tags/filters only *before* you have added your first
|
|
||||||
// template to the set (restrictions are statically checked). After you added one, it's not possible anymore
|
|
||||||
// (for your personal security).
|
|
||||||
//
|
|
||||||
// SandboxDirectories can be changed at runtime. Please synchronize the access to it if you need to change it
|
|
||||||
// after you've added your first template to the set. You *must* use this match pattern for your directories:
|
|
||||||
// http://golang.org/pkg/path/filepath/#Match
|
|
||||||
SandboxDirectories []string
|
|
||||||
firstTemplateCreated bool
|
firstTemplateCreated bool
|
||||||
bannedTags map[string]bool
|
bannedTags map[string]bool
|
||||||
bannedFilters map[string]bool
|
bannedFilters map[string]bool
|
||||||
|
@ -53,11 +54,13 @@ type TemplateSet struct {
|
||||||
templateCacheMutex sync.Mutex
|
templateCacheMutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create your own template sets to separate different kind of templates (e. g. web from mail templates) with
|
// NewSet can be used to create sets with different kind of templates
|
||||||
// different globals or other configurations (like base directories).
|
// (e. g. web from mail templates), with different globals or
|
||||||
func NewSet(name string) *TemplateSet {
|
// other configurations.
|
||||||
|
func NewSet(name string, loader TemplateLoader) *TemplateSet {
|
||||||
return &TemplateSet{
|
return &TemplateSet{
|
||||||
name: name,
|
name: name,
|
||||||
|
loader: loader,
|
||||||
Globals: make(Context),
|
Globals: make(Context),
|
||||||
bannedTags: make(map[string]bool),
|
bannedTags: make(map[string]bool),
|
||||||
bannedFilters: make(map[string]bool),
|
bannedFilters: make(map[string]bool),
|
||||||
|
@ -65,151 +68,157 @@ func NewSet(name string) *TemplateSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this function to set your template set's base directory. This directory will be used for any relative
|
func (set *TemplateSet) resolveFilename(tpl *Template, path string) string {
|
||||||
// path in filters, tags and From*-functions to determine your template.
|
name := ""
|
||||||
func (set *TemplateSet) SetBaseDirectory(name string) error {
|
if tpl != nil && tpl.isTplString {
|
||||||
// Make the path absolute
|
return path
|
||||||
if !filepath.IsAbs(name) {
|
|
||||||
abs, err := filepath.Abs(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
name = abs
|
if tpl != nil {
|
||||||
|
name = tpl.name
|
||||||
}
|
}
|
||||||
|
return set.loader.Abs(name, path)
|
||||||
// Check for existence
|
|
||||||
fi, err := os.Stat(name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !fi.IsDir() {
|
|
||||||
return fmt.Errorf("The given path '%s' is not a directory.")
|
|
||||||
}
|
|
||||||
|
|
||||||
set.baseDirectory = name
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (set *TemplateSet) BaseDirectory() string {
|
// BanTag bans a specific tag for this template set. See more in the documentation for TemplateSet.
|
||||||
return set.baseDirectory
|
func (set *TemplateSet) BanTag(name string) error {
|
||||||
}
|
|
||||||
|
|
||||||
// Ban a specific tag for this template set. See more in the documentation for TemplateSet.
|
|
||||||
func (set *TemplateSet) BanTag(name string) {
|
|
||||||
_, has := tags[name]
|
_, has := tags[name]
|
||||||
if !has {
|
if !has {
|
||||||
panic(fmt.Sprintf("Tag '%s' not found.", name))
|
return errors.Errorf("tag '%s' not found", name)
|
||||||
}
|
}
|
||||||
if set.firstTemplateCreated {
|
if set.firstTemplateCreated {
|
||||||
panic("You cannot ban any tags after you've added your first template to your template set.")
|
return errors.New("you cannot ban any tags after you've added your first template to your template set")
|
||||||
}
|
}
|
||||||
_, has = set.bannedTags[name]
|
_, has = set.bannedTags[name]
|
||||||
if has {
|
if has {
|
||||||
panic(fmt.Sprintf("Tag '%s' is already banned.", name))
|
return errors.Errorf("tag '%s' is already banned", name)
|
||||||
}
|
}
|
||||||
set.bannedTags[name] = true
|
set.bannedTags[name] = true
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ban a specific filter for this template set. See more in the documentation for TemplateSet.
|
// BanFilter bans a specific filter for this template set. See more in the documentation for TemplateSet.
|
||||||
func (set *TemplateSet) BanFilter(name string) {
|
func (set *TemplateSet) BanFilter(name string) error {
|
||||||
_, has := filters[name]
|
_, has := filters[name]
|
||||||
if !has {
|
if !has {
|
||||||
panic(fmt.Sprintf("Filter '%s' not found.", name))
|
return errors.Errorf("filter '%s' not found", name)
|
||||||
}
|
}
|
||||||
if set.firstTemplateCreated {
|
if set.firstTemplateCreated {
|
||||||
panic("You cannot ban any filters after you've added your first template to your template set.")
|
return errors.New("you cannot ban any filters after you've added your first template to your template set")
|
||||||
}
|
}
|
||||||
_, has = set.bannedFilters[name]
|
_, has = set.bannedFilters[name]
|
||||||
if has {
|
if has {
|
||||||
panic(fmt.Sprintf("Filter '%s' is already banned.", name))
|
return errors.Errorf("filter '%s' is already banned", name)
|
||||||
}
|
}
|
||||||
set.bannedFilters[name] = true
|
set.bannedFilters[name] = true
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromCache() is a convenient method to cache templates. It is thread-safe
|
// FromCache is a convenient method to cache templates. It is thread-safe
|
||||||
// and will only compile the template associated with a filename once.
|
// and will only compile the template associated with a filename once.
|
||||||
// If TemplateSet.Debug is true (for example during development phase),
|
// If TemplateSet.Debug is true (for example during development phase),
|
||||||
// FromCache() will not cache the template and instead recompile it on any
|
// FromCache() will not cache the template and instead recompile it on any
|
||||||
// call (to make changes to a template live instantaneously).
|
// call (to make changes to a template live instantaneously).
|
||||||
// Like FromFile(), FromCache() takes a relative path to a set base directory.
|
|
||||||
// Sandbox restrictions apply (if given).
|
|
||||||
func (set *TemplateSet) FromCache(filename string) (*Template, error) {
|
func (set *TemplateSet) FromCache(filename string) (*Template, error) {
|
||||||
if set.Debug {
|
if set.Debug {
|
||||||
// Recompile on any request
|
// Recompile on any request
|
||||||
return set.FromFile(filename)
|
return set.FromFile(filename)
|
||||||
} else {
|
}
|
||||||
// Cache the template
|
// Cache the template
|
||||||
cleaned_filename := set.resolveFilename(nil, filename)
|
cleanedFilename := set.resolveFilename(nil, filename)
|
||||||
|
|
||||||
set.templateCacheMutex.Lock()
|
set.templateCacheMutex.Lock()
|
||||||
defer set.templateCacheMutex.Unlock()
|
defer set.templateCacheMutex.Unlock()
|
||||||
|
|
||||||
tpl, has := set.templateCache[cleaned_filename]
|
tpl, has := set.templateCache[cleanedFilename]
|
||||||
|
|
||||||
// Cache miss
|
// Cache miss
|
||||||
if !has {
|
if !has {
|
||||||
tpl, err := set.FromFile(cleaned_filename)
|
tpl, err := set.FromFile(cleanedFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
set.templateCache[cleaned_filename] = tpl
|
set.templateCache[cleanedFilename] = tpl
|
||||||
return tpl, nil
|
return tpl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache hit
|
// Cache hit
|
||||||
return tpl, nil
|
return tpl, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads a template from string and returns a Template instance.
|
// FromString loads a template from string and returns a Template instance.
|
||||||
func (set *TemplateSet) FromString(tpl string) (*Template, error) {
|
func (set *TemplateSet) FromString(tpl string) (*Template, error) {
|
||||||
set.firstTemplateCreated = true
|
set.firstTemplateCreated = true
|
||||||
|
|
||||||
|
return newTemplateString(set, []byte(tpl))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromBytes loads a template from bytes and returns a Template instance.
|
||||||
|
func (set *TemplateSet) FromBytes(tpl []byte) (*Template, error) {
|
||||||
|
set.firstTemplateCreated = true
|
||||||
|
|
||||||
return newTemplateString(set, tpl)
|
return newTemplateString(set, tpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads a template from a filename and returns a Template instance.
|
// FromFile loads a template from a filename and returns a Template instance.
|
||||||
// If a base directory is set, the filename must be either relative to it
|
|
||||||
// or be an absolute path. Sandbox restrictions (SandboxDirectories) apply
|
|
||||||
// if given.
|
|
||||||
func (set *TemplateSet) FromFile(filename string) (*Template, error) {
|
func (set *TemplateSet) FromFile(filename string) (*Template, error) {
|
||||||
set.firstTemplateCreated = true
|
set.firstTemplateCreated = true
|
||||||
|
|
||||||
buf, err := ioutil.ReadFile(set.resolveFilename(nil, filename))
|
fd, err := set.loader.Get(set.resolveFilename(nil, filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &Error{
|
return nil, &Error{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Sender: "fromfile",
|
Sender: "fromfile",
|
||||||
ErrorMsg: err.Error(),
|
OrigError: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newTemplate(set, filename, false, string(buf))
|
buf, err := ioutil.ReadAll(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &Error{
|
||||||
|
Filename: filename,
|
||||||
|
Sender: "fromfile",
|
||||||
|
OrigError: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newTemplate(set, filename, false, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shortcut; renders a template string directly. Panics when providing a
|
// RenderTemplateString is a shortcut and renders a template string directly.
|
||||||
// malformed template or an error occurs during execution.
|
func (set *TemplateSet) RenderTemplateString(s string, ctx Context) (string, error) {
|
||||||
func (set *TemplateSet) RenderTemplateString(s string, ctx Context) string {
|
|
||||||
set.firstTemplateCreated = true
|
set.firstTemplateCreated = true
|
||||||
|
|
||||||
tpl := Must(set.FromString(s))
|
tpl := Must(set.FromString(s))
|
||||||
result, err := tpl.Execute(ctx)
|
result, err := tpl.Execute(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return "", err
|
||||||
}
|
}
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shortcut; renders a template file directly. Panics when providing a
|
// RenderTemplateBytes is a shortcut and renders template bytes directly.
|
||||||
// malformed template or an error occurs during execution.
|
func (set *TemplateSet) RenderTemplateBytes(b []byte, ctx Context) (string, error) {
|
||||||
func (set *TemplateSet) RenderTemplateFile(fn string, ctx Context) string {
|
set.firstTemplateCreated = true
|
||||||
|
|
||||||
|
tpl := Must(set.FromBytes(b))
|
||||||
|
result, err := tpl.Execute(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderTemplateFile is a shortcut and renders a template file directly.
|
||||||
|
func (set *TemplateSet) RenderTemplateFile(fn string, ctx Context) (string, error) {
|
||||||
set.firstTemplateCreated = true
|
set.firstTemplateCreated = true
|
||||||
|
|
||||||
tpl := Must(set.FromFile(fn))
|
tpl := Must(set.FromFile(fn))
|
||||||
result, err := tpl.Execute(ctx)
|
result, err := tpl.Execute(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return "", err
|
||||||
}
|
}
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (set *TemplateSet) logf(format string, args ...interface{}) {
|
func (set *TemplateSet) logf(format string, args ...interface{}) {
|
||||||
|
@ -218,58 +227,6 @@ func (set *TemplateSet) logf(format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolves a filename relative to the base directory. Absolute paths are allowed.
|
|
||||||
// If sandbox restrictions are given (SandboxDirectories), they will be respected and checked.
|
|
||||||
// On sandbox restriction violation, resolveFilename() panics.
|
|
||||||
func (set *TemplateSet) resolveFilename(tpl *Template, filename string) (resolved_path string) {
|
|
||||||
if len(set.SandboxDirectories) > 0 {
|
|
||||||
defer func() {
|
|
||||||
// Remove any ".." or other crap
|
|
||||||
resolved_path = filepath.Clean(resolved_path)
|
|
||||||
|
|
||||||
// Make the path absolute
|
|
||||||
abs_path, err := filepath.Abs(resolved_path)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
resolved_path = abs_path
|
|
||||||
|
|
||||||
// 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, resolved_path)
|
|
||||||
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'", resolved_path)
|
|
||||||
resolved_path = ""
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
if filepath.IsAbs(filename) {
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
|
|
||||||
if set.baseDirectory == "" {
|
|
||||||
if tpl != nil {
|
|
||||||
if tpl.is_tpl_string {
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
base := filepath.Dir(tpl.name)
|
|
||||||
return filepath.Join(base, filename)
|
|
||||||
}
|
|
||||||
return filename
|
|
||||||
} else {
|
|
||||||
return filepath.Join(set.baseDirectory, filename)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logging function (internally used)
|
// Logging function (internally used)
|
||||||
func logf(format string, items ...interface{}) {
|
func logf(format string, items ...interface{}) {
|
||||||
if debug {
|
if debug {
|
||||||
|
@ -279,13 +236,18 @@ func logf(format string, items ...interface{}) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
debug bool // internal debugging
|
debug bool // internal debugging
|
||||||
logger = log.New(os.Stdout, "[pongo2] ", log.LstdFlags)
|
logger = log.New(os.Stdout, "[pongo2] ", log.LstdFlags|log.Lshortfile)
|
||||||
|
|
||||||
// Creating a default set
|
// DefaultLoader allows the default un-sandboxed access to the local file
|
||||||
DefaultSet = NewSet("default")
|
// system and is being used by the DefaultSet.
|
||||||
|
DefaultLoader = MustNewLocalFileSystemLoader("")
|
||||||
|
|
||||||
|
// DefaultSet is a set created for you for convinience reasons.
|
||||||
|
DefaultSet = NewSet("default", DefaultLoader)
|
||||||
|
|
||||||
// Methods on the default set
|
// Methods on the default set
|
||||||
FromString = DefaultSet.FromString
|
FromString = DefaultSet.FromString
|
||||||
|
FromBytes = DefaultSet.FromBytes
|
||||||
FromFile = DefaultSet.FromFile
|
FromFile = DefaultSet.FromFile
|
||||||
FromCache = DefaultSet.FromCache
|
FromCache = DefaultSet.FromCache
|
||||||
RenderTemplateString = DefaultSet.RenderTemplateString
|
RenderTemplateString = DefaultSet.RenderTemplateString
|
||||||
|
|
50
vendor/github.com/flosch/pongo2/template_tests/comment.tpl
generated
vendored
Normal file
50
vendor/github.com/flosch/pongo2/template_tests/comment.tpl
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
empty single line comment
|
||||||
|
{# #}
|
||||||
|
|
||||||
|
filled single line comment
|
||||||
|
{# testing single line comment #}
|
||||||
|
|
||||||
|
filled single line comment with valid tags
|
||||||
|
{# testing single line comment {% if thing %}{% endif %} #}
|
||||||
|
|
||||||
|
filled single line comment with invalid tags
|
||||||
|
{# testing single line comment {% if thing %} #}
|
||||||
|
|
||||||
|
filled single line comment with invalid syntax
|
||||||
|
{# testing single line comment {% if thing('') %}wow{% endif %} #}
|
||||||
|
|
||||||
|
empty block comment
|
||||||
|
{% comment %}{% endcomment %}
|
||||||
|
|
||||||
|
filled text single line block comment
|
||||||
|
{% comment %}filled block comment {% endcomment %}
|
||||||
|
|
||||||
|
empty multi line block comment
|
||||||
|
{% comment %}
|
||||||
|
|
||||||
|
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
block comment with other tags inside of it
|
||||||
|
{% comment %}
|
||||||
|
{{ thing_goes_here }}
|
||||||
|
{% if stuff %}do stuff{% endif %}
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
block comment with invalid tags inside of it
|
||||||
|
{% comment %}
|
||||||
|
{% if thing %}
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
block comment with invalid syntax inside of it
|
||||||
|
{% comment %}
|
||||||
|
{% thing('') %}
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
Regular tags between comments to verify it doesn't break in the lexer
|
||||||
|
{% if hello %}
|
||||||
|
{% endif %}
|
||||||
|
after if
|
||||||
|
{% comment %}All done{% endcomment %}
|
||||||
|
|
||||||
|
end of file
|
39
vendor/github.com/flosch/pongo2/template_tests/comment.tpl.out
generated
vendored
Normal file
39
vendor/github.com/flosch/pongo2/template_tests/comment.tpl.out
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
empty single line comment
|
||||||
|
|
||||||
|
|
||||||
|
filled single line comment
|
||||||
|
|
||||||
|
|
||||||
|
filled single line comment with valid tags
|
||||||
|
|
||||||
|
|
||||||
|
filled single line comment with invalid tags
|
||||||
|
|
||||||
|
|
||||||
|
filled single line comment with invalid syntax
|
||||||
|
|
||||||
|
|
||||||
|
empty block comment
|
||||||
|
|
||||||
|
|
||||||
|
filled text single line block comment
|
||||||
|
|
||||||
|
|
||||||
|
empty multi line block comment
|
||||||
|
|
||||||
|
|
||||||
|
block comment with other tags inside of it
|
||||||
|
|
||||||
|
|
||||||
|
block comment with invalid tags inside of it
|
||||||
|
|
||||||
|
|
||||||
|
block comment with invalid syntax inside of it
|
||||||
|
|
||||||
|
|
||||||
|
Regular tags between comments to verify it doesn't break in the lexer
|
||||||
|
|
||||||
|
after if
|
||||||
|
|
||||||
|
|
||||||
|
end of file
|
16
vendor/github.com/flosch/pongo2/template_tests/expressions.tpl
generated
vendored
16
vendor/github.com/flosch/pongo2/template_tests/expressions.tpl
generated
vendored
|
@ -46,8 +46,24 @@ in/not in
|
||||||
{{ 7 in simple.intmap }}
|
{{ 7 in simple.intmap }}
|
||||||
{{ !(5 in simple.intmap) }}
|
{{ !(5 in simple.intmap) }}
|
||||||
{{ not(7 in simple.intmap) }}
|
{{ not(7 in simple.intmap) }}
|
||||||
|
{{ 1 in simple.multiple_item_list }}
|
||||||
|
{{ 4 in simple.multiple_item_list }}
|
||||||
|
{{ !(4 in simple.multiple_item_list) }}
|
||||||
|
{{ "Hello" in simple.misc_list }}
|
||||||
|
{{ "Hello2" in simple.misc_list }}
|
||||||
|
{{ 99 in simple.misc_list }}
|
||||||
|
{{ False in simple.misc_list }}
|
||||||
|
|
||||||
issue #48 (associativity for infix operators)
|
issue #48 (associativity for infix operators)
|
||||||
{{ 34/3*3 }}
|
{{ 34/3*3 }}
|
||||||
{{ 10 + 24 / 6 / 2 }}
|
{{ 10 + 24 / 6 / 2 }}
|
||||||
{{ 6 - 4 - 2 }}
|
{{ 6 - 4 - 2 }}
|
||||||
|
|
||||||
|
issue #64 (uint comparison with int const)
|
||||||
|
{{ simple.uint }}
|
||||||
|
{{ simple.uint == 8 }}
|
||||||
|
{{ simple.uint == 9 }}
|
||||||
|
{{ simple.uint >= 8 }}
|
||||||
|
{{ simple.uint <= 8 }}
|
||||||
|
{{ simple.uint < 8 }}
|
||||||
|
{{ simple.uint > 8 }}
|
16
vendor/github.com/flosch/pongo2/template_tests/expressions.tpl.out
generated
vendored
16
vendor/github.com/flosch/pongo2/template_tests/expressions.tpl.out
generated
vendored
|
@ -46,8 +46,24 @@ True
|
||||||
False
|
False
|
||||||
False
|
False
|
||||||
True
|
True
|
||||||
|
True
|
||||||
|
False
|
||||||
|
True
|
||||||
|
True
|
||||||
|
False
|
||||||
|
True
|
||||||
|
False
|
||||||
|
|
||||||
issue #48 (associativity for infix operators)
|
issue #48 (associativity for infix operators)
|
||||||
33
|
33
|
||||||
12
|
12
|
||||||
0
|
0
|
||||||
|
|
||||||
|
issue #64 (uint comparison with int const)
|
||||||
|
8
|
||||||
|
True
|
||||||
|
False
|
||||||
|
True
|
||||||
|
True
|
||||||
|
False
|
||||||
|
False
|
3
vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl
generated
vendored
Normal file
3
vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends "inheritance/base.tpl" %}
|
||||||
|
|
||||||
|
{% block content %}{{ block.Super }}extends-level-1{% endblock %}
|
1
vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl.out
generated
vendored
Normal file
1
vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl.out
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Start#This is base's bodyDefault contentextends-level-1#End
|
3
vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl
generated
vendored
Normal file
3
vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends "extends_super.tpl" %}
|
||||||
|
|
||||||
|
{% block content %}{{ block.Super }}extends-level-2{% endblock %}
|
1
vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl.out
generated
vendored
Normal file
1
vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl.out
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Start#This is base's bodyDefault contentextends-level-1extends-level-2#End
|
1
vendor/github.com/flosch/pongo2/template_tests/filters-execution.err
generated
vendored
1
vendor/github.com/flosch/pongo2/template_tests/filters-execution.err
generated
vendored
|
@ -1,3 +1,4 @@
|
||||||
{{ -(true || false) }}
|
{{ -(true || false) }}
|
||||||
{{ simple.func_add("test", 5) }}
|
{{ simple.func_add("test", 5) }}
|
||||||
|
{% for item in simple.multiple_item_list %} {{ simple.func_add("test", 5) }} {% endfor %}
|
||||||
{{ simple.func_variadic_sum_int("foo") }}
|
{{ simple.func_variadic_sum_int("foo") }}
|
1
vendor/github.com/flosch/pongo2/template_tests/filters-execution.err.out
generated
vendored
1
vendor/github.com/flosch/pongo2/template_tests/filters-execution.err.out
generated
vendored
|
@ -1,3 +1,4 @@
|
||||||
.*where: execution.*Negative sign on a non\-number expression
|
.*where: execution.*Negative sign on a non\-number expression
|
||||||
.*Function input argument 0 of 'simple.func_add' must be of type int or \*pongo2.Value \(not string\).
|
.*Function input argument 0 of 'simple.func_add' must be of type int or \*pongo2.Value \(not string\).
|
||||||
|
.*Function input argument 0 of 'simple.func_add' must be of type int or \*pongo2.Value \(not string\).
|
||||||
.*Function variadic input argument of 'simple.func_variadic_sum_int' must be of type int or \*pongo2.Value \(not string\).
|
.*Function variadic input argument of 'simple.func_variadic_sum_int' must be of type int or \*pongo2.Value \(not string\).
|
3
vendor/github.com/flosch/pongo2/template_tests/filters.tpl
generated
vendored
3
vendor/github.com/flosch/pongo2/template_tests/filters.tpl
generated
vendored
|
@ -176,6 +176,9 @@ floatformat
|
||||||
join
|
join
|
||||||
{{ simple.misc_list|join:", " }}
|
{{ simple.misc_list|join:", " }}
|
||||||
|
|
||||||
|
split
|
||||||
|
{{ "Hello, 99, 3.140000, good"|split:", "|join:", " }}
|
||||||
|
|
||||||
stringformat
|
stringformat
|
||||||
{{ simple.float|stringformat:"%.2f" }}
|
{{ simple.float|stringformat:"%.2f" }}
|
||||||
{{ simple.uint|stringformat:"Test: %d" }}
|
{{ simple.uint|stringformat:"Test: %d" }}
|
||||||
|
|
7
vendor/github.com/flosch/pongo2/template_tests/filters.tpl.out
generated
vendored
7
vendor/github.com/flosch/pongo2/template_tests/filters.tpl.out
generated
vendored
|
@ -105,7 +105,7 @@ h
|
||||||
|
|
||||||
first
|
first
|
||||||
T
|
T
|
||||||
<pongo2.comment Value>
|
<pongo2_test.comment Value>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ T
|
||||||
|
|
||||||
last
|
last
|
||||||
t
|
t
|
||||||
<pongo2.comment Value>
|
<pongo2_test.comment Value>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -176,6 +176,9 @@ floatformat
|
||||||
join
|
join
|
||||||
Hello, 99, 3.140000, good
|
Hello, 99, 3.140000, good
|
||||||
|
|
||||||
|
split
|
||||||
|
Hello, 99, 3.140000, good
|
||||||
|
|
||||||
stringformat
|
stringformat
|
||||||
3.14
|
3.14
|
||||||
Test: 8
|
Test: 8
|
||||||
|
|
18
vendor/github.com/flosch/pongo2/template_tests/for.tpl
generated
vendored
18
vendor/github.com/flosch/pongo2/template_tests/for.tpl
generated
vendored
|
@ -7,3 +7,21 @@
|
||||||
|
|
||||||
reversed
|
reversed
|
||||||
'{% for item in simple.multiple_item_list reversed %}{{ item }} {% endfor %}'
|
'{% for item in simple.multiple_item_list reversed %}{{ item }} {% endfor %}'
|
||||||
|
|
||||||
|
sorted string map
|
||||||
|
'{% for key in simple.strmap sorted %}{{ key }} {% endfor %}'
|
||||||
|
|
||||||
|
sorted int map
|
||||||
|
'{% for key in simple.intmap sorted %}{{ key }} {% endfor %}'
|
||||||
|
|
||||||
|
sorted int list
|
||||||
|
'{% for key in simple.unsorted_int_list sorted %}{{ key }} {% endfor %}'
|
||||||
|
|
||||||
|
reversed sorted int list
|
||||||
|
'{% for key in simple.unsorted_int_list reversed sorted %}{{ key }} {% endfor %}'
|
||||||
|
|
||||||
|
reversed sorted string map
|
||||||
|
'{% for key in simple.strmap reversed sorted %}{{ key }} {% endfor %}'
|
||||||
|
|
||||||
|
reversed sorted int map
|
||||||
|
'{% for key in simple.intmap reversed sorted %}{{ key }} {% endfor %}'
|
||||||
|
|
18
vendor/github.com/flosch/pongo2/template_tests/for.tpl.out
generated
vendored
18
vendor/github.com/flosch/pongo2/template_tests/for.tpl.out
generated
vendored
|
@ -17,3 +17,21 @@
|
||||||
|
|
||||||
reversed
|
reversed
|
||||||
'55 34 21 13 8 5 3 2 1 1 '
|
'55 34 21 13 8 5 3 2 1 1 '
|
||||||
|
|
||||||
|
sorted string map
|
||||||
|
'aab abc bcd gh ukq zab '
|
||||||
|
|
||||||
|
sorted int map
|
||||||
|
'1 2 5 '
|
||||||
|
|
||||||
|
sorted int list
|
||||||
|
'1 22 192 249 581 8271 9999 1828591 '
|
||||||
|
|
||||||
|
reversed sorted int list
|
||||||
|
'1828591 9999 8271 581 249 192 22 1 '
|
||||||
|
|
||||||
|
reversed sorted string map
|
||||||
|
'zab ukq gh bcd abc aab '
|
||||||
|
|
||||||
|
reversed sorted int map
|
||||||
|
'5 2 1 '
|
||||||
|
|
1
vendor/github.com/flosch/pongo2/template_tests/if.tpl
generated
vendored
1
vendor/github.com/flosch/pongo2/template_tests/if.tpl
generated
vendored
|
@ -9,6 +9,7 @@
|
||||||
{% if 5 in simple.intmap %}5 in simple.intmap{% endif %}
|
{% if 5 in simple.intmap %}5 in simple.intmap{% endif %}
|
||||||
{% if !0.0 %}!0.0{% endif %}
|
{% if !0.0 %}!0.0{% endif %}
|
||||||
{% if !0 %}!0{% endif %}
|
{% if !0 %}!0{% endif %}
|
||||||
|
{% if not complex.post %}true{% else %}false{% endif %}
|
||||||
{% if simple.number == 43 %}no{% else %}42{% endif %}
|
{% if simple.number == 43 %}no{% else %}42{% endif %}
|
||||||
{% if simple.number < 42 %}false{% elif simple.number > 42 %}no{% elif simple.number >= 42 %}yes{% else %}no{% endif %}
|
{% if simple.number < 42 %}false{% elif simple.number > 42 %}no{% elif simple.number >= 42 %}yes{% else %}no{% endif %}
|
||||||
{% if simple.number < 42 %}false{% elif simple.number > 42 %}no{% elif simple.number != 42 %}no{% else %}yes{% endif %}
|
{% if simple.number < 42 %}false{% elif simple.number > 42 %}no{% elif simple.number != 42 %}no{% else %}yes{% endif %}
|
||||||
|
|
1
vendor/github.com/flosch/pongo2/template_tests/if.tpl.out
generated
vendored
1
vendor/github.com/flosch/pongo2/template_tests/if.tpl.out
generated
vendored
|
@ -9,6 +9,7 @@ text field in complex.post
|
||||||
5 in simple.intmap
|
5 in simple.intmap
|
||||||
!0.0
|
!0.0
|
||||||
!0
|
!0
|
||||||
|
false
|
||||||
42
|
42
|
||||||
yes
|
yes
|
||||||
yes
|
yes
|
||||||
|
|
3
vendor/github.com/flosch/pongo2/template_tests/includes.tpl
generated
vendored
3
vendor/github.com/flosch/pongo2/template_tests/includes.tpl
generated
vendored
|
@ -1,4 +1,7 @@
|
||||||
Start '{% include "includes.helper" %}' End
|
Start '{% include "includes.helper" %}' End
|
||||||
|
Start '{% include "includes.helper" if_exists %}' End
|
||||||
Start '{% include "includes.helper" with what_am_i=simple.name only %}' End
|
Start '{% include "includes.helper" with what_am_i=simple.name only %}' End
|
||||||
Start '{% include "includes.helper" with what_am_i=simple.name %}' End
|
Start '{% include "includes.helper" with what_am_i=simple.name %}' End
|
||||||
Start '{% include simple.included_file|lower with number=7 what_am_i="guest" %}' End
|
Start '{% include simple.included_file|lower with number=7 what_am_i="guest" %}' End
|
||||||
|
Start '{% include "includes.helper.not_exists" if_exists %}' End
|
||||||
|
Start '{% include simple.included_file_not_exists if_exists with number=7 what_am_i="guest" %}' End
|
3
vendor/github.com/flosch/pongo2/template_tests/includes.tpl.out
generated
vendored
3
vendor/github.com/flosch/pongo2/template_tests/includes.tpl.out
generated
vendored
|
@ -1,4 +1,7 @@
|
||||||
Start 'I'm 11' End
|
Start 'I'm 11' End
|
||||||
|
Start 'I'm 11' End
|
||||||
Start 'I'm john doe' End
|
Start 'I'm john doe' End
|
||||||
Start 'I'm john doe11' End
|
Start 'I'm john doe11' End
|
||||||
Start 'I'm guest7' End
|
Start 'I'm guest7' End
|
||||||
|
Start '' End
|
||||||
|
Start '' End
|
2
vendor/github.com/flosch/pongo2/template_tests/macro-compilation.err.out
generated
vendored
2
vendor/github.com/flosch/pongo2/template_tests/macro-compilation.err.out
generated
vendored
|
@ -1 +1 @@
|
||||||
.*Another macro with name 'test_override' already exported.
|
.*another macro with name 'test_override' already exported
|
2
vendor/github.com/flosch/pongo2/template_tests/macro-execution.err.out
generated
vendored
2
vendor/github.com/flosch/pongo2/template_tests/macro-execution.err.out
generated
vendored
|
@ -1 +1 @@
|
||||||
.*Context key name 'number' clashes with macro 'number'.
|
.*context key name 'number' clashes with macro 'number'
|
2
vendor/github.com/flosch/pongo2/template_tests/pongo2ctx.tpl.out
generated
vendored
2
vendor/github.com/flosch/pongo2/template_tests/pongo2ctx.tpl.out
generated
vendored
|
@ -1 +1 @@
|
||||||
v3
|
dev
|
15
vendor/github.com/flosch/pongo2/template_tests/quotes.tpl
generated
vendored
Normal file
15
vendor/github.com/flosch/pongo2/template_tests/quotes.tpl
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Variables
|
||||||
|
{{ "hello" }}
|
||||||
|
{{ 'hello' }}
|
||||||
|
{{ "hell'o" }}
|
||||||
|
|
||||||
|
Filters
|
||||||
|
{{ 'Test'|slice:'1:3' }}
|
||||||
|
{{ '<div class=\"foo\"><ul class=\"foo\"><li class=\"foo\"><p class=\"foo\">This is a long test which will be cutted after some chars.</p></li></ul></div>'|truncatechars_html:25 }}
|
||||||
|
{{ '<a name="link"><p>This </a>is a long test which will be cutted after some chars.</p>'|truncatechars_html:25 }}
|
||||||
|
|
||||||
|
Tags
|
||||||
|
{% if 'Text' in complex.post %}text field in complex.post{% endif %}
|
||||||
|
|
||||||
|
Functions
|
||||||
|
{{ simple.func_variadic('hello') }}
|
15
vendor/github.com/flosch/pongo2/template_tests/quotes.tpl.out
generated
vendored
Normal file
15
vendor/github.com/flosch/pongo2/template_tests/quotes.tpl.out
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
Variables
|
||||||
|
hello
|
||||||
|
hello
|
||||||
|
hell'o
|
||||||
|
|
||||||
|
Filters
|
||||||
|
es
|
||||||
|
<div class="foo"><ul class="foo"><li class="foo"><p class="foo">This is a long test wh...</p></li></ul></div>
|
||||||
|
<a name="link"><p>This </a>is a long test wh...</p>
|
||||||
|
|
||||||
|
Tags
|
||||||
|
text field in complex.post
|
||||||
|
|
||||||
|
Functions
|
||||||
|
hello
|
1
vendor/github.com/flosch/pongo2/template_tests/set.tpl
generated
vendored
1
vendor/github.com/flosch/pongo2/template_tests/set.tpl
generated
vendored
|
@ -3,3 +3,4 @@
|
||||||
{{ new_var }}{% for item in simple.misc_list %}
|
{{ new_var }}{% for item in simple.misc_list %}
|
||||||
{% set new_var = item %}{{ new_var }}{% endfor %}
|
{% set new_var = item %}{{ new_var }}{% endfor %}
|
||||||
{{ new_var }}
|
{{ new_var }}
|
||||||
|
{% set car=someUndefinedVar %}{{ car.Drive }}No Panic
|
1
vendor/github.com/flosch/pongo2/template_tests/set.tpl.out
generated
vendored
1
vendor/github.com/flosch/pongo2/template_tests/set.tpl.out
generated
vendored
|
@ -6,3 +6,4 @@ Hello
|
||||||
3.140000
|
3.140000
|
||||||
good
|
good
|
||||||
world
|
world
|
||||||
|
No Panic
|
2
vendor/github.com/flosch/pongo2/template_tests/variables.tpl
generated
vendored
2
vendor/github.com/flosch/pongo2/template_tests/variables.tpl
generated
vendored
|
@ -11,3 +11,5 @@
|
||||||
{{ simple.uint }}
|
{{ simple.uint }}
|
||||||
{{ simple.uint|integer }}
|
{{ simple.uint|integer }}
|
||||||
{{ simple.uint|float }}
|
{{ simple.uint|float }}
|
||||||
|
{{ simple.multiple_item_list.10 }}
|
||||||
|
{{ simple.multiple_item_list.4 }}
|
||||||
|
|
2
vendor/github.com/flosch/pongo2/template_tests/variables.tpl.out
generated
vendored
2
vendor/github.com/flosch/pongo2/template_tests/variables.tpl.out
generated
vendored
|
@ -11,3 +11,5 @@ True
|
||||||
8
|
8
|
||||||
8
|
8
|
||||||
8.000000
|
8.000000
|
||||||
|
|
||||||
|
5
|
||||||
|
|
2
vendor/github.com/flosch/pongo2/template_tests/with.tpl.out
generated
vendored
2
vendor/github.com/flosch/pongo2/template_tests/with.tpl.out
generated
vendored
|
@ -11,6 +11,6 @@ Start 'I'm guest7' End
|
||||||
Start 'Hi number 10! Will not be overridden inside the block. I'm john doe, 50 years old.I have 10 children.' End
|
Start 'Hi number 10! Will not be overridden inside the block. I'm john doe, 50 years old.I have 10 children.' End
|
||||||
|
|
||||||
more with tests
|
more with tests
|
||||||
<pongo2.user Value>
|
<pongo2_test.user Value>
|
||||||
user1
|
user1
|
||||||
user3
|
user3
|
179
vendor/github.com/flosch/pongo2/value.go
generated
vendored
179
vendor/github.com/flosch/pongo2/value.go
generated
vendored
|
@ -3,6 +3,7 @@ package pongo2
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -12,7 +13,7 @@ type Value struct {
|
||||||
safe bool // used to indicate whether a Value needs explicit escaping in the template
|
safe bool // used to indicate whether a Value needs explicit escaping in the template
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts any given value to a pongo2.Value
|
// AsValue converts any given value to a pongo2.Value
|
||||||
// Usually being used within own functions passed to a template
|
// Usually being used within own functions passed to a template
|
||||||
// through a Context or within filter functions.
|
// through a Context or within filter functions.
|
||||||
//
|
//
|
||||||
|
@ -24,7 +25,7 @@ func AsValue(i interface{}) *Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like AsValue, but does not apply the 'escape' filter.
|
// AsSafeValue works like AsValue, but does not apply the 'escape' filter.
|
||||||
func AsSafeValue(i interface{}) *Value {
|
func AsSafeValue(i interface{}) *Value {
|
||||||
return &Value{
|
return &Value{
|
||||||
val: reflect.ValueOf(i),
|
val: reflect.ValueOf(i),
|
||||||
|
@ -39,23 +40,23 @@ func (v *Value) getResolvedValue() reflect.Value {
|
||||||
return v.val
|
return v.val
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value is a string
|
// IsString checks whether the underlying value is a string
|
||||||
func (v *Value) IsString() bool {
|
func (v *Value) IsString() bool {
|
||||||
return v.getResolvedValue().Kind() == reflect.String
|
return v.getResolvedValue().Kind() == reflect.String
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value is a bool
|
// IsBool checks whether the underlying value is a bool
|
||||||
func (v *Value) IsBool() bool {
|
func (v *Value) IsBool() bool {
|
||||||
return v.getResolvedValue().Kind() == reflect.Bool
|
return v.getResolvedValue().Kind() == reflect.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value is a float
|
// IsFloat checks whether the underlying value is a float
|
||||||
func (v *Value) IsFloat() bool {
|
func (v *Value) IsFloat() bool {
|
||||||
return v.getResolvedValue().Kind() == reflect.Float32 ||
|
return v.getResolvedValue().Kind() == reflect.Float32 ||
|
||||||
v.getResolvedValue().Kind() == reflect.Float64
|
v.getResolvedValue().Kind() == reflect.Float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value is an integer
|
// IsInteger checks whether the underlying value is an integer
|
||||||
func (v *Value) IsInteger() bool {
|
func (v *Value) IsInteger() bool {
|
||||||
return v.getResolvedValue().Kind() == reflect.Int ||
|
return v.getResolvedValue().Kind() == reflect.Int ||
|
||||||
v.getResolvedValue().Kind() == reflect.Int8 ||
|
v.getResolvedValue().Kind() == reflect.Int8 ||
|
||||||
|
@ -69,19 +70,19 @@ func (v *Value) IsInteger() bool {
|
||||||
v.getResolvedValue().Kind() == reflect.Uint64
|
v.getResolvedValue().Kind() == reflect.Uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value is either an integer
|
// IsNumber checks whether the underlying value is either an integer
|
||||||
// or a float.
|
// or a float.
|
||||||
func (v *Value) IsNumber() bool {
|
func (v *Value) IsNumber() bool {
|
||||||
return v.IsInteger() || v.IsFloat()
|
return v.IsInteger() || v.IsFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value is NIL
|
// IsNil checks whether the underlying value is NIL
|
||||||
func (v *Value) IsNil() bool {
|
func (v *Value) IsNil() bool {
|
||||||
//fmt.Printf("%+v\n", v.getResolvedValue().Type().String())
|
//fmt.Printf("%+v\n", v.getResolvedValue().Type().String())
|
||||||
return !v.getResolvedValue().IsValid()
|
return !v.getResolvedValue().IsValid()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a string for the underlying value. If this value is not
|
// String returns a string for the underlying value. If this value is not
|
||||||
// of type string, pongo2 tries to convert it. Currently the following
|
// of type string, pongo2 tries to convert it. Currently the following
|
||||||
// types for underlying values are supported:
|
// types for underlying values are supported:
|
||||||
//
|
//
|
||||||
|
@ -111,9 +112,8 @@ func (v *Value) String() string {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
if v.Bool() {
|
if v.Bool() {
|
||||||
return "True"
|
return "True"
|
||||||
} else {
|
|
||||||
return "False"
|
|
||||||
}
|
}
|
||||||
|
return "False"
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if t, ok := v.Interface().(fmt.Stringer); ok {
|
if t, ok := v.Interface().(fmt.Stringer); ok {
|
||||||
return t.String()
|
return t.String()
|
||||||
|
@ -124,7 +124,7 @@ func (v *Value) String() string {
|
||||||
return v.getResolvedValue().String()
|
return v.getResolvedValue().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the underlying value as an integer (converts the underlying
|
// Integer returns the underlying value as an integer (converts the underlying
|
||||||
// value, if necessary). If it's not possible to convert the underlying value,
|
// value, if necessary). If it's not possible to convert the underlying value,
|
||||||
// it will return 0.
|
// it will return 0.
|
||||||
func (v *Value) Integer() int {
|
func (v *Value) Integer() int {
|
||||||
|
@ -148,7 +148,7 @@ func (v *Value) Integer() int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the underlying value as a float (converts the underlying
|
// Float returns the underlying value as a float (converts the underlying
|
||||||
// value, if necessary). If it's not possible to convert the underlying value,
|
// value, if necessary). If it's not possible to convert the underlying value,
|
||||||
// it will return 0.0.
|
// it will return 0.0.
|
||||||
func (v *Value) Float() float64 {
|
func (v *Value) Float() float64 {
|
||||||
|
@ -172,7 +172,7 @@ func (v *Value) Float() float64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the underlying value as bool. If the value is not bool, false
|
// Bool returns the underlying value as bool. If the value is not bool, false
|
||||||
// will always be returned. If you're looking for true/false-evaluation of the
|
// will always be returned. If you're looking for true/false-evaluation of the
|
||||||
// underlying value, have a look on the IsTrue()-function.
|
// underlying value, have a look on the IsTrue()-function.
|
||||||
func (v *Value) Bool() bool {
|
func (v *Value) Bool() bool {
|
||||||
|
@ -185,7 +185,7 @@ func (v *Value) Bool() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tries to evaluate the underlying value the Pythonic-way:
|
// IsTrue tries to evaluate the underlying value the Pythonic-way:
|
||||||
//
|
//
|
||||||
// Returns TRUE in one the following cases:
|
// Returns TRUE in one the following cases:
|
||||||
//
|
//
|
||||||
|
@ -217,7 +217,7 @@ func (v *Value) IsTrue() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tries to negate the underlying value. It's mainly used for
|
// Negate tries to negate the underlying value. It's mainly used for
|
||||||
// the NOT-operator and in conjunction with a call to
|
// the NOT-operator and in conjunction with a call to
|
||||||
// return_value.IsTrue() afterwards.
|
// return_value.IsTrue() afterwards.
|
||||||
//
|
//
|
||||||
|
@ -229,26 +229,26 @@ func (v *Value) Negate() *Value {
|
||||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
if v.Integer() != 0 {
|
if v.Integer() != 0 {
|
||||||
return AsValue(0)
|
return AsValue(0)
|
||||||
} else {
|
|
||||||
return AsValue(1)
|
|
||||||
}
|
}
|
||||||
|
return AsValue(1)
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
if v.Float() != 0.0 {
|
if v.Float() != 0.0 {
|
||||||
return AsValue(float64(0.0))
|
return AsValue(float64(0.0))
|
||||||
} else {
|
|
||||||
return AsValue(float64(1.1))
|
|
||||||
}
|
}
|
||||||
|
return AsValue(float64(1.1))
|
||||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
|
||||||
return AsValue(v.getResolvedValue().Len() == 0)
|
return AsValue(v.getResolvedValue().Len() == 0)
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return AsValue(!v.getResolvedValue().Bool())
|
return AsValue(!v.getResolvedValue().Bool())
|
||||||
|
case reflect.Struct:
|
||||||
|
return AsValue(false)
|
||||||
default:
|
default:
|
||||||
logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
|
logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
|
||||||
return AsValue(true)
|
return AsValue(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the length for an array, chan, map, slice or string.
|
// Len returns the length for an array, chan, map, slice or string.
|
||||||
// Otherwise it will return 0.
|
// Otherwise it will return 0.
|
||||||
func (v *Value) Len() int {
|
func (v *Value) Len() int {
|
||||||
switch v.getResolvedValue().Kind() {
|
switch v.getResolvedValue().Kind() {
|
||||||
|
@ -263,7 +263,7 @@ func (v *Value) Len() int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slices an array, slice or string. Otherwise it will
|
// Slice slices an array, slice or string. Otherwise it will
|
||||||
// return an empty []int.
|
// return an empty []int.
|
||||||
func (v *Value) Slice(i, j int) *Value {
|
func (v *Value) Slice(i, j int) *Value {
|
||||||
switch v.getResolvedValue().Kind() {
|
switch v.getResolvedValue().Kind() {
|
||||||
|
@ -278,7 +278,7 @@ func (v *Value) Slice(i, j int) *Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the i-th item of an array, slice or string. Otherwise
|
// Index gets the i-th item of an array, slice or string. Otherwise
|
||||||
// it will return NIL.
|
// it will return NIL.
|
||||||
func (v *Value) Index(i int) *Value {
|
func (v *Value) Index(i int) *Value {
|
||||||
switch v.getResolvedValue().Kind() {
|
switch v.getResolvedValue().Kind() {
|
||||||
|
@ -301,7 +301,7 @@ func (v *Value) Index(i int) *Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value (which must be of type struct, map,
|
// Contains checks whether the underlying value (which must be of type struct, map,
|
||||||
// string, array or slice) contains of another Value (e. g. used to check
|
// string, array or slice) contains of another Value (e. g. used to check
|
||||||
// whether a struct contains of a specific field or a map contains a specific key).
|
// whether a struct contains of a specific field or a map contains a specific key).
|
||||||
//
|
//
|
||||||
|
@ -310,25 +310,32 @@ func (v *Value) Index(i int) *Value {
|
||||||
func (v *Value) Contains(other *Value) bool {
|
func (v *Value) Contains(other *Value) bool {
|
||||||
switch v.getResolvedValue().Kind() {
|
switch v.getResolvedValue().Kind() {
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
field_value := v.getResolvedValue().FieldByName(other.String())
|
fieldValue := v.getResolvedValue().FieldByName(other.String())
|
||||||
return field_value.IsValid()
|
return fieldValue.IsValid()
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
var map_value reflect.Value
|
var mapValue reflect.Value
|
||||||
switch other.Interface().(type) {
|
switch other.Interface().(type) {
|
||||||
case int:
|
case int:
|
||||||
map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||||
case string:
|
case string:
|
||||||
map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||||
default:
|
default:
|
||||||
logf("Value.Contains() does not support lookup type '%s'\n", other.getResolvedValue().Kind().String())
|
logf("Value.Contains() does not support lookup type '%s'\n", other.getResolvedValue().Kind().String())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return map_value.IsValid()
|
return mapValue.IsValid()
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return strings.Contains(v.getResolvedValue().String(), other.String())
|
return strings.Contains(v.getResolvedValue().String(), other.String())
|
||||||
|
|
||||||
// TODO: reflect.Array, reflect.Slice
|
case reflect.Slice, reflect.Array:
|
||||||
|
for i := 0; i < v.getResolvedValue().Len(); i++ {
|
||||||
|
item := v.getResolvedValue().Index(i)
|
||||||
|
if other.Interface() == item.Interface() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logf("Value.Contains() not available for type: %s\n", v.getResolvedValue().Kind().String())
|
logf("Value.Contains() not available for type: %s\n", v.getResolvedValue().Kind().String())
|
||||||
|
@ -336,7 +343,7 @@ func (v *Value) Contains(other *Value) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether the underlying value is of type array, slice or string.
|
// CanSlice checks whether the underlying value is of type array, slice or string.
|
||||||
// You normally would use CanSlice() before using the Slice() operation.
|
// You normally would use CanSlice() before using the Slice() operation.
|
||||||
func (v *Value) CanSlice() bool {
|
func (v *Value) CanSlice() bool {
|
||||||
switch v.getResolvedValue().Kind() {
|
switch v.getResolvedValue().Kind() {
|
||||||
|
@ -346,7 +353,7 @@ func (v *Value) CanSlice() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterates over a map, array, slice or a string. It calls the
|
// Iterate iterates over a map, array, slice or a string. It calls the
|
||||||
// function's first argument for every value with the following arguments:
|
// function's first argument for every value with the following arguments:
|
||||||
//
|
//
|
||||||
// idx current 0-index
|
// idx current 0-index
|
||||||
|
@ -357,16 +364,23 @@ func (v *Value) CanSlice() bool {
|
||||||
// If the underlying value has no items or is not one of the types above,
|
// If the underlying value has no items or is not one of the types above,
|
||||||
// the empty function (function's second argument) will be called.
|
// the empty function (function's second argument) will be called.
|
||||||
func (v *Value) Iterate(fn func(idx, count int, key, value *Value) bool, empty func()) {
|
func (v *Value) Iterate(fn func(idx, count int, key, value *Value) bool, empty func()) {
|
||||||
v.IterateOrder(fn, empty, false)
|
v.IterateOrder(fn, empty, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Like Value.Iterate, but can iterate through an array/slice/string in reverse. Does
|
// IterateOrder behaves like Value.Iterate, but can iterate through an array/slice/string in reverse. Does
|
||||||
// not affect the iteration through a map because maps don't have any particular order.
|
// not affect the iteration through a map because maps don't have any particular order.
|
||||||
func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, empty func(), reverse bool) {
|
// However, you can force an order using the `sorted` keyword (and even use `reversed sorted`).
|
||||||
|
func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, empty func(), reverse bool, sorted bool) {
|
||||||
switch v.getResolvedValue().Kind() {
|
switch v.getResolvedValue().Kind() {
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
// Reverse not needed for maps, since they are not ordered
|
keys := sortedKeys(v.getResolvedValue().MapKeys())
|
||||||
keys := v.getResolvedValue().MapKeys()
|
if sorted {
|
||||||
|
if reverse {
|
||||||
|
sort.Sort(sort.Reverse(keys))
|
||||||
|
} else {
|
||||||
|
sort.Sort(keys)
|
||||||
|
}
|
||||||
|
}
|
||||||
keyLen := len(keys)
|
keyLen := len(keys)
|
||||||
for idx, key := range keys {
|
for idx, key := range keys {
|
||||||
value := v.getResolvedValue().MapIndex(key)
|
value := v.getResolvedValue().MapIndex(key)
|
||||||
|
@ -379,27 +393,44 @@ func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, em
|
||||||
}
|
}
|
||||||
return // done
|
return // done
|
||||||
case reflect.Array, reflect.Slice:
|
case reflect.Array, reflect.Slice:
|
||||||
|
var items valuesList
|
||||||
|
|
||||||
itemCount := v.getResolvedValue().Len()
|
itemCount := v.getResolvedValue().Len()
|
||||||
if itemCount > 0 {
|
for i := 0; i < itemCount; i++ {
|
||||||
if reverse {
|
items = append(items, &Value{val: v.getResolvedValue().Index(i)})
|
||||||
for i := itemCount - 1; i >= 0; i-- {
|
|
||||||
if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sorted {
|
||||||
|
if reverse {
|
||||||
|
sort.Sort(sort.Reverse(items))
|
||||||
|
} else {
|
||||||
|
sort.Sort(items)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < itemCount; i++ {
|
if reverse {
|
||||||
if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
|
for i := 0; i < itemCount/2; i++ {
|
||||||
return
|
items[i], items[itemCount-1-i] = items[itemCount-1-i], items[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(items) > 0 {
|
||||||
|
for idx, item := range items {
|
||||||
|
if !fn(idx, itemCount, item, nil) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
empty()
|
empty()
|
||||||
}
|
}
|
||||||
return // done
|
return // done
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
// TODO: Not utf8-compatible (utf8-decoding neccessary)
|
if sorted {
|
||||||
|
// TODO(flosch): Handle sorted
|
||||||
|
panic("TODO: handle sort for type string")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(flosch): Not utf8-compatible (utf8-decoding necessary)
|
||||||
charCount := v.getResolvedValue().Len()
|
charCount := v.getResolvedValue().Len()
|
||||||
if charCount > 0 {
|
if charCount > 0 {
|
||||||
if reverse {
|
if reverse {
|
||||||
|
@ -425,7 +456,7 @@ func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, em
|
||||||
empty()
|
empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gives you access to the underlying value.
|
// Interface gives you access to the underlying value.
|
||||||
func (v *Value) Interface() interface{} {
|
func (v *Value) Interface() interface{} {
|
||||||
if v.val.IsValid() {
|
if v.val.IsValid() {
|
||||||
return v.val.Interface()
|
return v.val.Interface()
|
||||||
|
@ -433,7 +464,57 @@ func (v *Value) Interface() interface{} {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether two values are containing the same value or object.
|
// EqualValueTo checks whether two values are containing the same value or object.
|
||||||
func (v *Value) EqualValueTo(other *Value) bool {
|
func (v *Value) EqualValueTo(other *Value) bool {
|
||||||
|
// comparison of uint with int fails using .Interface()-comparison (see issue #64)
|
||||||
|
if v.IsInteger() && other.IsInteger() {
|
||||||
|
return v.Integer() == other.Integer()
|
||||||
|
}
|
||||||
return v.Interface() == other.Interface()
|
return v.Interface() == other.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sortedKeys []reflect.Value
|
||||||
|
|
||||||
|
func (sk sortedKeys) Len() int {
|
||||||
|
return len(sk)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sk sortedKeys) Less(i, j int) bool {
|
||||||
|
vi := &Value{val: sk[i]}
|
||||||
|
vj := &Value{val: sk[j]}
|
||||||
|
switch {
|
||||||
|
case vi.IsInteger() && vj.IsInteger():
|
||||||
|
return vi.Integer() < vj.Integer()
|
||||||
|
case vi.IsFloat() && vj.IsFloat():
|
||||||
|
return vi.Float() < vj.Float()
|
||||||
|
default:
|
||||||
|
return vi.String() < vj.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sk sortedKeys) Swap(i, j int) {
|
||||||
|
sk[i], sk[j] = sk[j], sk[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
type valuesList []*Value
|
||||||
|
|
||||||
|
func (vl valuesList) Len() int {
|
||||||
|
return len(vl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vl valuesList) Less(i, j int) bool {
|
||||||
|
vi := vl[i]
|
||||||
|
vj := vl[j]
|
||||||
|
switch {
|
||||||
|
case vi.IsInteger() && vj.IsInteger():
|
||||||
|
return vi.Integer() < vj.Integer()
|
||||||
|
case vi.IsFloat() && vj.IsFloat():
|
||||||
|
return vi.Float() < vj.Float()
|
||||||
|
default:
|
||||||
|
return vi.String() < vj.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vl valuesList) Swap(i, j int) {
|
||||||
|
vl[i], vl[j] = vl[j], vl[i]
|
||||||
|
}
|
||||||
|
|
240
vendor/github.com/flosch/pongo2/variable.go
generated
vendored
240
vendor/github.com/flosch/pongo2/variable.go
generated
vendored
|
@ -1,11 +1,12 @@
|
||||||
package pongo2
|
package pongo2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -13,13 +14,18 @@ const (
|
||||||
varTypeIdent
|
varTypeIdent
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
typeOfValuePtr = reflect.TypeOf(new(Value))
|
||||||
|
typeOfExecCtxPtr = reflect.TypeOf(new(ExecutionContext))
|
||||||
|
)
|
||||||
|
|
||||||
type variablePart struct {
|
type variablePart struct {
|
||||||
typ int
|
typ int
|
||||||
s string
|
s string
|
||||||
i int
|
i int
|
||||||
|
|
||||||
is_function_call bool
|
isFunctionCall bool
|
||||||
calling_args []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
|
callingArgs []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
|
||||||
}
|
}
|
||||||
|
|
||||||
type functionCallArgument interface {
|
type functionCallArgument interface {
|
||||||
|
@ -28,119 +34,121 @@ type functionCallArgument interface {
|
||||||
|
|
||||||
// TODO: Add location tokens
|
// TODO: Add location tokens
|
||||||
type stringResolver struct {
|
type stringResolver struct {
|
||||||
location_token *Token
|
locationToken *Token
|
||||||
val string
|
val string
|
||||||
}
|
}
|
||||||
|
|
||||||
type intResolver struct {
|
type intResolver struct {
|
||||||
location_token *Token
|
locationToken *Token
|
||||||
val int
|
val int
|
||||||
}
|
}
|
||||||
|
|
||||||
type floatResolver struct {
|
type floatResolver struct {
|
||||||
location_token *Token
|
locationToken *Token
|
||||||
val float64
|
val float64
|
||||||
}
|
}
|
||||||
|
|
||||||
type boolResolver struct {
|
type boolResolver struct {
|
||||||
location_token *Token
|
locationToken *Token
|
||||||
val bool
|
val bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type variableResolver struct {
|
type variableResolver struct {
|
||||||
location_token *Token
|
locationToken *Token
|
||||||
|
|
||||||
parts []*variablePart
|
parts []*variablePart
|
||||||
}
|
}
|
||||||
|
|
||||||
type nodeFilteredVariable struct {
|
type nodeFilteredVariable struct {
|
||||||
location_token *Token
|
locationToken *Token
|
||||||
|
|
||||||
resolver IEvaluator
|
resolver IEvaluator
|
||||||
filterChain []*filterCall
|
filterChain []*filterCall
|
||||||
}
|
}
|
||||||
|
|
||||||
type nodeVariable struct {
|
type nodeVariable struct {
|
||||||
location_token *Token
|
locationToken *Token
|
||||||
expr IEvaluator
|
expr IEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *nodeFilteredVariable) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
type executionCtxEval struct{}
|
||||||
value, err := expr.Evaluate(ctx)
|
|
||||||
|
func (v *nodeFilteredVariable) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
|
value, err := v.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *variableResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (vr *variableResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := vr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *stringResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (s *stringResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := s.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *intResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (i *intResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := i.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *floatResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (f *floatResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := f.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (expr *boolResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (b *boolResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := expr.Evaluate(ctx)
|
value, err := b.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *nodeFilteredVariable) GetPositionToken() *Token {
|
func (v *nodeFilteredVariable) GetPositionToken() *Token {
|
||||||
return v.location_token
|
return v.locationToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *variableResolver) GetPositionToken() *Token {
|
func (vr *variableResolver) GetPositionToken() *Token {
|
||||||
return v.location_token
|
return vr.locationToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *stringResolver) GetPositionToken() *Token {
|
func (s *stringResolver) GetPositionToken() *Token {
|
||||||
return v.location_token
|
return s.locationToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *intResolver) GetPositionToken() *Token {
|
func (i *intResolver) GetPositionToken() *Token {
|
||||||
return v.location_token
|
return i.locationToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *floatResolver) GetPositionToken() *Token {
|
func (f *floatResolver) GetPositionToken() *Token {
|
||||||
return v.location_token
|
return f.locationToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *boolResolver) GetPositionToken() *Token {
|
func (b *boolResolver) GetPositionToken() *Token {
|
||||||
return v.location_token
|
return b.locationToken
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stringResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
func (s *stringResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
|
@ -179,7 +187,7 @@ func (nv *nodeVariable) FilterApplied(name string) bool {
|
||||||
return nv.expr.FilterApplied(name)
|
return nv.expr.FilterApplied(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nv *nodeVariable) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
func (nv *nodeVariable) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||||
value, err := nv.expr.Evaluate(ctx)
|
value, err := nv.expr.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -193,10 +201,14 @@ func (nv *nodeVariable) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Er
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.WriteString(value.String())
|
writer.WriteString(value.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (executionCtxEval) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
|
return AsValue(ctx), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vr *variableResolver) FilterApplied(name string) bool {
|
func (vr *variableResolver) FilterApplied(name string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -218,15 +230,15 @@ func (vr *variableResolver) String() string {
|
||||||
|
|
||||||
func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||||
var current reflect.Value
|
var current reflect.Value
|
||||||
var is_safe bool
|
var isSafe bool
|
||||||
|
|
||||||
for idx, part := range vr.parts {
|
for idx, part := range vr.parts {
|
||||||
if idx == 0 {
|
if idx == 0 {
|
||||||
// We're looking up the first part of the variable.
|
// We're looking up the first part of the variable.
|
||||||
// First we're having a look in our private
|
// First we're having a look in our private
|
||||||
// context (e. g. information provided by tags, like the forloop)
|
// context (e. g. information provided by tags, like the forloop)
|
||||||
val, in_private := ctx.Private[vr.parts[0].s]
|
val, inPrivate := ctx.Private[vr.parts[0].s]
|
||||||
if !in_private {
|
if !inPrivate {
|
||||||
// Nothing found? Then have a final lookup in the public context
|
// Nothing found? Then have a final lookup in the public context
|
||||||
val = ctx.Public[vr.parts[0].s]
|
val = ctx.Public[vr.parts[0].s]
|
||||||
}
|
}
|
||||||
|
@ -236,16 +248,16 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||||
|
|
||||||
// Before resolving the pointer, let's see if we have a method to call
|
// Before resolving the pointer, let's see if we have a method to call
|
||||||
// Problem with resolving the pointer is we're changing the receiver
|
// Problem with resolving the pointer is we're changing the receiver
|
||||||
is_func := false
|
isFunc := false
|
||||||
if part.typ == varTypeIdent {
|
if part.typ == varTypeIdent {
|
||||||
func_value := current.MethodByName(part.s)
|
funcValue := current.MethodByName(part.s)
|
||||||
if func_value.IsValid() {
|
if funcValue.IsValid() {
|
||||||
current = func_value
|
current = funcValue
|
||||||
is_func = true
|
isFunc = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_func {
|
if !isFunc {
|
||||||
// If current a pointer, resolve it
|
// If current a pointer, resolve it
|
||||||
if current.Kind() == reflect.Ptr {
|
if current.Kind() == reflect.Ptr {
|
||||||
current = current.Elem()
|
current = current.Elem()
|
||||||
|
@ -262,9 +274,14 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||||
// * slices/arrays/strings
|
// * slices/arrays/strings
|
||||||
switch current.Kind() {
|
switch current.Kind() {
|
||||||
case reflect.String, reflect.Array, reflect.Slice:
|
case reflect.String, reflect.Array, reflect.Slice:
|
||||||
|
if part.i >= 0 && current.Len() > part.i {
|
||||||
current = current.Index(part.i)
|
current = current.Index(part.i)
|
||||||
|
} else {
|
||||||
|
// In Django, exceeding the length of a list is just empty.
|
||||||
|
return AsValue(nil), nil
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Can't access an index on type %s (variable %s)",
|
return nil, errors.Errorf("Can't access an index on type %s (variable %s)",
|
||||||
current.Kind().String(), vr.String())
|
current.Kind().String(), vr.String())
|
||||||
}
|
}
|
||||||
case varTypeIdent:
|
case varTypeIdent:
|
||||||
|
@ -278,7 +295,7 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
current = current.MapIndex(reflect.ValueOf(part.s))
|
current = current.MapIndex(reflect.ValueOf(part.s))
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Can't access a field by name on type %s (variable %s)",
|
return nil, errors.Errorf("Can't access a field by name on type %s (variable %s)",
|
||||||
current.Kind().String(), vr.String())
|
current.Kind().String(), vr.String())
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -295,10 +312,10 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||||
// If current is a reflect.ValueOf(pongo2.Value), then unpack it
|
// If current is a reflect.ValueOf(pongo2.Value), then unpack it
|
||||||
// Happens in function calls (as a return value) or by injecting
|
// Happens in function calls (as a return value) or by injecting
|
||||||
// into the execution context (e.g. in a for-loop)
|
// into the execution context (e.g. in a for-loop)
|
||||||
if current.Type() == reflect.TypeOf(&Value{}) {
|
if current.Type() == typeOfValuePtr {
|
||||||
tmp_value := current.Interface().(*Value)
|
tmpValue := current.Interface().(*Value)
|
||||||
current = tmp_value.val
|
current = tmpValue.val
|
||||||
is_safe = tmp_value.safe
|
isSafe = tmpValue.safe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether this is an interface and resolve it where required
|
// Check whether this is an interface and resolve it where required
|
||||||
|
@ -307,86 +324,96 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the part is a function call
|
// Check if the part is a function call
|
||||||
if part.is_function_call || current.Kind() == reflect.Func {
|
if part.isFunctionCall || current.Kind() == reflect.Func {
|
||||||
// Check for callable
|
// Check for callable
|
||||||
if current.Kind() != reflect.Func {
|
if current.Kind() != reflect.Func {
|
||||||
return nil, fmt.Errorf("'%s' is not a function (it is %s).", vr.String(), current.Kind().String())
|
return nil, errors.Errorf("'%s' is not a function (it is %s)", vr.String(), current.Kind().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for correct function syntax and types
|
// Check for correct function syntax and types
|
||||||
// func(*Value, ...) *Value
|
// func(*Value, ...) *Value
|
||||||
t := current.Type()
|
t := current.Type()
|
||||||
|
currArgs := part.callingArgs
|
||||||
|
|
||||||
|
// If an implicit ExecCtx is needed
|
||||||
|
if t.NumIn() > 0 && t.In(0) == typeOfExecCtxPtr {
|
||||||
|
currArgs = append([]functionCallArgument{executionCtxEval{}}, currArgs...)
|
||||||
|
}
|
||||||
|
|
||||||
// Input arguments
|
// Input arguments
|
||||||
if len(part.calling_args) != t.NumIn() && !(len(part.calling_args) >= t.NumIn()-1 && t.IsVariadic()) {
|
if len(currArgs) != t.NumIn() && !(len(currArgs) >= t.NumIn()-1 && t.IsVariadic()) {
|
||||||
return nil,
|
return nil,
|
||||||
fmt.Errorf("Function input argument count (%d) of '%s' must be equal to the calling argument count (%d).",
|
errors.Errorf("Function input argument count (%d) of '%s' must be equal to the calling argument count (%d).",
|
||||||
t.NumIn(), vr.String(), len(part.calling_args))
|
t.NumIn(), vr.String(), len(currArgs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output arguments
|
// Output arguments
|
||||||
if t.NumOut() != 1 {
|
if t.NumOut() != 1 {
|
||||||
return nil, fmt.Errorf("'%s' must have exactly 1 output argument.", vr.String())
|
return nil, errors.Errorf("'%s' must have exactly 1 output argument", vr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate all parameters
|
// Evaluate all parameters
|
||||||
parameters := make([]reflect.Value, 0)
|
var parameters []reflect.Value
|
||||||
|
|
||||||
num_args := t.NumIn()
|
numArgs := t.NumIn()
|
||||||
is_variadic := t.IsVariadic()
|
isVariadic := t.IsVariadic()
|
||||||
var fn_arg reflect.Type
|
var fnArg reflect.Type
|
||||||
|
|
||||||
for idx, arg := range part.calling_args {
|
for idx, arg := range currArgs {
|
||||||
pv, err := arg.Evaluate(ctx)
|
pv, err := arg.Evaluate(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_variadic {
|
if isVariadic {
|
||||||
if idx >= t.NumIn()-1 {
|
if idx >= t.NumIn()-1 {
|
||||||
fn_arg = t.In(num_args - 1).Elem()
|
fnArg = t.In(numArgs - 1).Elem()
|
||||||
} else {
|
} else {
|
||||||
fn_arg = t.In(idx)
|
fnArg = t.In(idx)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fn_arg = t.In(idx)
|
fnArg = t.In(idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fn_arg != reflect.TypeOf(new(Value)) {
|
if fnArg != typeOfValuePtr {
|
||||||
// Function's argument is not a *pongo2.Value, then we have to check whether input argument is of the same type as the function's argument
|
// Function's argument is not a *pongo2.Value, then we have to check whether input argument is of the same type as the function's argument
|
||||||
if !is_variadic {
|
if !isVariadic {
|
||||||
if fn_arg != reflect.TypeOf(pv.Interface()) && fn_arg.Kind() != reflect.Interface {
|
if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
|
||||||
return nil, fmt.Errorf("Function input argument %d of '%s' must be of type %s or *pongo2.Value (not %T).",
|
return nil, errors.Errorf("Function input argument %d of '%s' must be of type %s or *pongo2.Value (not %T).",
|
||||||
idx, vr.String(), fn_arg.String(), pv.Interface())
|
idx, vr.String(), fnArg.String(), pv.Interface())
|
||||||
} else {
|
}
|
||||||
// Function's argument has another type, using the interface-value
|
// Function's argument has another type, using the interface-value
|
||||||
parameters = append(parameters, reflect.ValueOf(pv.Interface()))
|
parameters = append(parameters, reflect.ValueOf(pv.Interface()))
|
||||||
|
} else {
|
||||||
|
if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
|
||||||
|
return nil, errors.Errorf("Function variadic input argument of '%s' must be of type %s or *pongo2.Value (not %T).",
|
||||||
|
vr.String(), fnArg.String(), pv.Interface())
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if fn_arg != reflect.TypeOf(pv.Interface()) && fn_arg.Kind() != reflect.Interface {
|
|
||||||
return nil, fmt.Errorf("Function variadic input argument of '%s' must be of type %s or *pongo2.Value (not %T).",
|
|
||||||
vr.String(), fn_arg.String(), pv.Interface())
|
|
||||||
} else {
|
|
||||||
// Function's argument has another type, using the interface-value
|
// Function's argument has another type, using the interface-value
|
||||||
parameters = append(parameters, reflect.ValueOf(pv.Interface()))
|
parameters = append(parameters, reflect.ValueOf(pv.Interface()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Function's argument is a *pongo2.Value
|
// Function's argument is a *pongo2.Value
|
||||||
parameters = append(parameters, reflect.ValueOf(pv))
|
parameters = append(parameters, reflect.ValueOf(pv))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if any of the values are invalid
|
||||||
|
for _, p := range parameters {
|
||||||
|
if p.Kind() == reflect.Invalid {
|
||||||
|
return nil, errors.Errorf("Calling a function using an invalid parameter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Call it and get first return parameter back
|
// Call it and get first return parameter back
|
||||||
rv := current.Call(parameters)[0]
|
rv := current.Call(parameters)[0]
|
||||||
|
|
||||||
if rv.Type() != reflect.TypeOf(new(Value)) {
|
if rv.Type() != typeOfValuePtr {
|
||||||
current = reflect.ValueOf(rv.Interface())
|
current = reflect.ValueOf(rv.Interface())
|
||||||
} else {
|
} else {
|
||||||
// Return the function call value
|
// Return the function call value
|
||||||
current = rv.Interface().(*Value).val
|
current = rv.Interface().(*Value).val
|
||||||
is_safe = rv.Interface().(*Value).safe
|
isSafe = rv.Interface().(*Value).safe
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,14 +421,15 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||||
// Value is not valid (e. g. NIL value)
|
// Value is not valid (e. g. NIL value)
|
||||||
return AsValue(nil), nil
|
return AsValue(nil), nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &Value{val: current, safe: is_safe}, nil
|
return &Value{val: current, safe: isSafe}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vr *variableResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
func (vr *variableResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||||
value, err := vr.resolve(ctx)
|
value, err := vr.resolve(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return AsValue(nil), ctx.Error(err.Error(), vr.location_token)
|
return AsValue(nil), ctx.Error(err.Error(), vr.locationToken)
|
||||||
}
|
}
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
@ -436,7 +464,7 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
||||||
t := p.Current()
|
t := p.Current()
|
||||||
|
|
||||||
if t == nil {
|
if t == nil {
|
||||||
return nil, p.Error("Unexpected EOF, expected a number, string, keyword or identifier.", p.last_token)
|
return nil, p.Error("Unexpected EOF, expected a number, string, keyword or identifier.", p.lastToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is first part a number or a string, there's nothing to resolve (because there's only to return the value then)
|
// Is first part a number or a string, there's nothing to resolve (because there's only to return the value then)
|
||||||
|
@ -460,25 +488,25 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
||||||
return nil, p.Error(err.Error(), t)
|
return nil, p.Error(err.Error(), t)
|
||||||
}
|
}
|
||||||
fr := &floatResolver{
|
fr := &floatResolver{
|
||||||
location_token: t,
|
locationToken: t,
|
||||||
val: f,
|
val: f,
|
||||||
}
|
}
|
||||||
return fr, nil
|
return fr, nil
|
||||||
} else {
|
}
|
||||||
i, err := strconv.Atoi(t.Val)
|
i, err := strconv.Atoi(t.Val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, p.Error(err.Error(), t)
|
return nil, p.Error(err.Error(), t)
|
||||||
}
|
}
|
||||||
nr := &intResolver{
|
nr := &intResolver{
|
||||||
location_token: t,
|
locationToken: t,
|
||||||
val: i,
|
val: i,
|
||||||
}
|
}
|
||||||
return nr, nil
|
return nr, nil
|
||||||
}
|
|
||||||
case TokenString:
|
case TokenString:
|
||||||
p.Consume()
|
p.Consume()
|
||||||
sr := &stringResolver{
|
sr := &stringResolver{
|
||||||
location_token: t,
|
locationToken: t,
|
||||||
val: t.Val,
|
val: t.Val,
|
||||||
}
|
}
|
||||||
return sr, nil
|
return sr, nil
|
||||||
|
@ -487,13 +515,13 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
||||||
switch t.Val {
|
switch t.Val {
|
||||||
case "true":
|
case "true":
|
||||||
br := &boolResolver{
|
br := &boolResolver{
|
||||||
location_token: t,
|
locationToken: t,
|
||||||
val: true,
|
val: true,
|
||||||
}
|
}
|
||||||
return br, nil
|
return br, nil
|
||||||
case "false":
|
case "false":
|
||||||
br := &boolResolver{
|
br := &boolResolver{
|
||||||
location_token: t,
|
locationToken: t,
|
||||||
val: false,
|
val: false,
|
||||||
}
|
}
|
||||||
return br, nil
|
return br, nil
|
||||||
|
@ -503,7 +531,7 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver := &variableResolver{
|
resolver := &variableResolver{
|
||||||
location_token: t,
|
locationToken: t,
|
||||||
}
|
}
|
||||||
|
|
||||||
// First part of a variable MUST be an identifier
|
// First part of a variable MUST be an identifier
|
||||||
|
@ -551,26 +579,26 @@ variableLoop:
|
||||||
} else {
|
} else {
|
||||||
// EOF
|
// EOF
|
||||||
return nil, p.Error("Unexpected EOF, expected either IDENTIFIER or NUMBER after DOT.",
|
return nil, p.Error("Unexpected EOF, expected either IDENTIFIER or NUMBER after DOT.",
|
||||||
p.last_token)
|
p.lastToken)
|
||||||
}
|
}
|
||||||
} else if p.Match(TokenSymbol, "(") != nil {
|
} else if p.Match(TokenSymbol, "(") != nil {
|
||||||
// Function call
|
// Function call
|
||||||
// FunctionName '(' Comma-separated list of expressions ')'
|
// FunctionName '(' Comma-separated list of expressions ')'
|
||||||
part := resolver.parts[len(resolver.parts)-1]
|
part := resolver.parts[len(resolver.parts)-1]
|
||||||
part.is_function_call = true
|
part.isFunctionCall = true
|
||||||
argumentLoop:
|
argumentLoop:
|
||||||
for {
|
for {
|
||||||
if p.Remaining() == 0 {
|
if p.Remaining() == 0 {
|
||||||
return nil, p.Error("Unexpected EOF, expected function call argument list.", p.last_token)
|
return nil, p.Error("Unexpected EOF, expected function call argument list.", p.lastToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Peek(TokenSymbol, ")") == nil {
|
if p.Peek(TokenSymbol, ")") == nil {
|
||||||
// No closing bracket, so we're parsing an expression
|
// No closing bracket, so we're parsing an expression
|
||||||
expr_arg, err := p.ParseExpression()
|
exprArg, err := p.ParseExpression()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
part.calling_args = append(part.calling_args, expr_arg)
|
part.callingArgs = append(part.callingArgs, exprArg)
|
||||||
|
|
||||||
if p.Match(TokenSymbol, ")") != nil {
|
if p.Match(TokenSymbol, ")") != nil {
|
||||||
// If there's a closing bracket after an expression, we will stop parsing the arguments
|
// If there's a closing bracket after an expression, we will stop parsing the arguments
|
||||||
|
@ -601,7 +629,7 @@ variableLoop:
|
||||||
|
|
||||||
func (p *Parser) parseVariableOrLiteralWithFilter() (*nodeFilteredVariable, *Error) {
|
func (p *Parser) parseVariableOrLiteralWithFilter() (*nodeFilteredVariable, *Error) {
|
||||||
v := &nodeFilteredVariable{
|
v := &nodeFilteredVariable{
|
||||||
location_token: p.Current(),
|
locationToken: p.Current(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the variable name
|
// Parse the variable name
|
||||||
|
@ -621,15 +649,13 @@ filterLoop:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sandbox filter restriction
|
// Check sandbox filter restriction
|
||||||
if _, is_banned := p.template.set.bannedFilters[filter.name]; is_banned {
|
if _, isBanned := p.template.set.bannedFilters[filter.name]; isBanned {
|
||||||
return nil, p.Error(fmt.Sprintf("Usage of filter '%s' is not allowed (sandbox restriction active).", filter.name), nil)
|
return nil, p.Error(fmt.Sprintf("Usage of filter '%s' is not allowed (sandbox restriction active).", filter.name), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
v.filterChain = append(v.filterChain, filter)
|
v.filterChain = append(v.filterChain, filter)
|
||||||
|
|
||||||
continue filterLoop
|
continue filterLoop
|
||||||
|
|
||||||
return nil, p.Error("This token is not allowed within a variable.", nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
@ -637,7 +663,7 @@ filterLoop:
|
||||||
|
|
||||||
func (p *Parser) parseVariableElement() (INode, *Error) {
|
func (p *Parser) parseVariableElement() (INode, *Error) {
|
||||||
node := &nodeVariable{
|
node := &nodeVariable{
|
||||||
location_token: p.Current(),
|
locationToken: p.Current(),
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Consume() // consume '{{'
|
p.Consume() // consume '{{'
|
||||||
|
|
23
vendor/github.com/juju/errors/.gitignore
generated
vendored
Normal file
23
vendor/github.com/juju/errors/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
191
vendor/github.com/juju/errors/LICENSE
generated
vendored
Normal file
191
vendor/github.com/juju/errors/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
All files in this repository are licensed as follows. If you contribute
|
||||||
|
to this repository, it is assumed that you license your contribution
|
||||||
|
under the same license unless you state otherwise.
|
||||||
|
|
||||||
|
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
|
||||||
|
|
||||||
|
This software is licensed under the LGPLv3, included below.
|
||||||
|
|
||||||
|
As a special exception to the GNU Lesser General Public License version 3
|
||||||
|
("LGPL3"), the copyright holders of this Library give you permission to
|
||||||
|
convey to a third party a Combined Work that links statically or dynamically
|
||||||
|
to this Library without providing any Minimal Corresponding Source or
|
||||||
|
Minimal Application Code as set out in 4d or providing the installation
|
||||||
|
information set out in section 4e, provided that you comply with the other
|
||||||
|
provisions of LGPL3 and provided that you meet, for the Application the
|
||||||
|
terms and conditions of the license(s) which apply to the Application.
|
||||||
|
|
||||||
|
Except as stated in this special exception, the provisions of LGPL3 will
|
||||||
|
continue to comply in full to this Library. If you modify this Library, you
|
||||||
|
may apply this exception to your version of this Library, but you are not
|
||||||
|
obliged to do so. If you do not wish to do so, delete this exception
|
||||||
|
statement from your version. This exception does not (and cannot) modify any
|
||||||
|
license terms which apply to the Application, with which you must still
|
||||||
|
comply.
|
||||||
|
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
11
vendor/github.com/juju/errors/Makefile
generated
vendored
Normal file
11
vendor/github.com/juju/errors/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
default: check
|
||||||
|
|
||||||
|
check:
|
||||||
|
go test && go test -compiler gccgo
|
||||||
|
|
||||||
|
docs:
|
||||||
|
godoc2md github.com/juju/errors > README.md
|
||||||
|
sed -i 's|\[godoc-link-here\]|[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)|' README.md
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: default check docs
|
543
vendor/github.com/juju/errors/README.md
generated
vendored
Normal file
543
vendor/github.com/juju/errors/README.md
generated
vendored
Normal file
|
@ -0,0 +1,543 @@
|
||||||
|
|
||||||
|
# errors
|
||||||
|
import "github.com/juju/errors"
|
||||||
|
|
||||||
|
[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)
|
||||||
|
|
||||||
|
The juju/errors provides an easy way to annotate errors without losing the
|
||||||
|
orginal error context.
|
||||||
|
|
||||||
|
The exported `New` and `Errorf` functions are designed to replace the
|
||||||
|
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
|
||||||
|
error is there, but the package also records the location at which the error
|
||||||
|
was created.
|
||||||
|
|
||||||
|
A primary use case for this library is to add extra context any time an
|
||||||
|
error is returned from a function.
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
This instead becomes:
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
which just records the file and line number of the Trace call, or
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Annotate(err, "more context")
|
||||||
|
}
|
||||||
|
|
||||||
|
which also adds an annotation to the error.
|
||||||
|
|
||||||
|
When you want to check to see if an error is of a particular type, a helper
|
||||||
|
function is normally exported by the package that returned the error, like the
|
||||||
|
`os` package does. The underlying cause of the error is available using the
|
||||||
|
`Cause` function.
|
||||||
|
|
||||||
|
|
||||||
|
os.IsNotExist(errors.Cause(err))
|
||||||
|
|
||||||
|
The result of the `Error()` call on an annotated error is the annotations joined
|
||||||
|
with colons, then the result of the `Error()` method for the underlying error
|
||||||
|
that was the cause.
|
||||||
|
|
||||||
|
|
||||||
|
err := errors.Errorf("original")
|
||||||
|
err = errors.Annotatef(err, "context")
|
||||||
|
err = errors.Annotatef(err, "more context")
|
||||||
|
err.Error() -> "more context: context: original"
|
||||||
|
|
||||||
|
Obviously recording the file, line and functions is not very useful if you
|
||||||
|
cannot get them back out again.
|
||||||
|
|
||||||
|
|
||||||
|
errors.ErrorStack(err)
|
||||||
|
|
||||||
|
will return something like:
|
||||||
|
|
||||||
|
|
||||||
|
first error
|
||||||
|
github.com/juju/errors/annotation_test.go:193:
|
||||||
|
github.com/juju/errors/annotation_test.go:194: annotation
|
||||||
|
github.com/juju/errors/annotation_test.go:195:
|
||||||
|
github.com/juju/errors/annotation_test.go:196: more context
|
||||||
|
github.com/juju/errors/annotation_test.go:197:
|
||||||
|
|
||||||
|
The first error was generated by an external system, so there was no location
|
||||||
|
associated. The second, fourth, and last lines were generated with Trace calls,
|
||||||
|
and the other two through Annotate.
|
||||||
|
|
||||||
|
Sometimes when responding to an error you want to return a more specific error
|
||||||
|
for the situation.
|
||||||
|
|
||||||
|
|
||||||
|
if err := FindField(field); err != nil {
|
||||||
|
return errors.Wrap(err, errors.NotFoundf(field))
|
||||||
|
}
|
||||||
|
|
||||||
|
This returns an error where the complete error stack is still available, and
|
||||||
|
`errors.Cause()` will return the `NotFound` error.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## func AlreadyExistsf
|
||||||
|
``` go
|
||||||
|
func AlreadyExistsf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
AlreadyExistsf returns an error which satisfies IsAlreadyExists().
|
||||||
|
|
||||||
|
|
||||||
|
## func Annotate
|
||||||
|
``` go
|
||||||
|
func Annotate(other error, message string) error
|
||||||
|
```
|
||||||
|
Annotate is used to add extra context to an existing error. The location of
|
||||||
|
the Annotate call is recorded with the annotations. The file, line and
|
||||||
|
function are also recorded.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Annotate(err, "failed to frombulate")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## func Annotatef
|
||||||
|
``` go
|
||||||
|
func Annotatef(other error, format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
Annotatef is used to add extra context to an existing error. The location of
|
||||||
|
the Annotate call is recorded with the annotations. The file, line and
|
||||||
|
function are also recorded.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Annotatef(err, "failed to frombulate the %s", arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## func Cause
|
||||||
|
``` go
|
||||||
|
func Cause(err error) error
|
||||||
|
```
|
||||||
|
Cause returns the cause of the given error. This will be either the
|
||||||
|
original error, or the result of a Wrap or Mask call.
|
||||||
|
|
||||||
|
Cause is the usual way to diagnose errors that may have been wrapped by
|
||||||
|
the other errors functions.
|
||||||
|
|
||||||
|
|
||||||
|
## func DeferredAnnotatef
|
||||||
|
``` go
|
||||||
|
func DeferredAnnotatef(err *error, format string, args ...interface{})
|
||||||
|
```
|
||||||
|
DeferredAnnotatef annotates the given error (when it is not nil) with the given
|
||||||
|
format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
|
||||||
|
does nothing. This method is used in a defer statement in order to annotate any
|
||||||
|
resulting error with the same message.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
|
||||||
|
|
||||||
|
|
||||||
|
## func Details
|
||||||
|
``` go
|
||||||
|
func Details(err error) string
|
||||||
|
```
|
||||||
|
Details returns information about the stack of errors wrapped by err, in
|
||||||
|
the format:
|
||||||
|
|
||||||
|
|
||||||
|
[{filename:99: error one} {otherfile:55: cause of error one}]
|
||||||
|
|
||||||
|
This is a terse alternative to ErrorStack as it returns a single line.
|
||||||
|
|
||||||
|
|
||||||
|
## func ErrorStack
|
||||||
|
``` go
|
||||||
|
func ErrorStack(err error) string
|
||||||
|
```
|
||||||
|
ErrorStack returns a string representation of the annotated error. If the
|
||||||
|
error passed as the parameter is not an annotated error, the result is
|
||||||
|
simply the result of the Error() method on that error.
|
||||||
|
|
||||||
|
If the error is an annotated error, a multi-line string is returned where
|
||||||
|
each line represents one entry in the annotation stack. The full filename
|
||||||
|
from the call stack is used in the output.
|
||||||
|
|
||||||
|
|
||||||
|
first error
|
||||||
|
github.com/juju/errors/annotation_test.go:193:
|
||||||
|
github.com/juju/errors/annotation_test.go:194: annotation
|
||||||
|
github.com/juju/errors/annotation_test.go:195:
|
||||||
|
github.com/juju/errors/annotation_test.go:196: more context
|
||||||
|
github.com/juju/errors/annotation_test.go:197:
|
||||||
|
|
||||||
|
|
||||||
|
## func Errorf
|
||||||
|
``` go
|
||||||
|
func Errorf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
Errorf creates a new annotated error and records the location that the
|
||||||
|
error is created. This should be a drop in replacement for fmt.Errorf.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
return errors.Errorf("validation failed: %s", message)
|
||||||
|
|
||||||
|
|
||||||
|
## func IsAlreadyExists
|
||||||
|
``` go
|
||||||
|
func IsAlreadyExists(err error) bool
|
||||||
|
```
|
||||||
|
IsAlreadyExists reports whether the error was created with
|
||||||
|
AlreadyExistsf() or NewAlreadyExists().
|
||||||
|
|
||||||
|
|
||||||
|
## func IsNotFound
|
||||||
|
``` go
|
||||||
|
func IsNotFound(err error) bool
|
||||||
|
```
|
||||||
|
IsNotFound reports whether err was created with NotFoundf() or
|
||||||
|
NewNotFound().
|
||||||
|
|
||||||
|
|
||||||
|
## func IsNotImplemented
|
||||||
|
``` go
|
||||||
|
func IsNotImplemented(err error) bool
|
||||||
|
```
|
||||||
|
IsNotImplemented reports whether err was created with
|
||||||
|
NotImplementedf() or NewNotImplemented().
|
||||||
|
|
||||||
|
|
||||||
|
## func IsNotSupported
|
||||||
|
``` go
|
||||||
|
func IsNotSupported(err error) bool
|
||||||
|
```
|
||||||
|
IsNotSupported reports whether the error was created with
|
||||||
|
NotSupportedf() or NewNotSupported().
|
||||||
|
|
||||||
|
|
||||||
|
## func IsNotValid
|
||||||
|
``` go
|
||||||
|
func IsNotValid(err error) bool
|
||||||
|
```
|
||||||
|
IsNotValid reports whether the error was created with NotValidf() or
|
||||||
|
NewNotValid().
|
||||||
|
|
||||||
|
|
||||||
|
## func IsUnauthorized
|
||||||
|
``` go
|
||||||
|
func IsUnauthorized(err error) bool
|
||||||
|
```
|
||||||
|
IsUnauthorized reports whether err was created with Unauthorizedf() or
|
||||||
|
NewUnauthorized().
|
||||||
|
|
||||||
|
|
||||||
|
## func Mask
|
||||||
|
``` go
|
||||||
|
func Mask(other error) error
|
||||||
|
```
|
||||||
|
Mask hides the underlying error type, and records the location of the masking.
|
||||||
|
|
||||||
|
|
||||||
|
## func Maskf
|
||||||
|
``` go
|
||||||
|
func Maskf(other error, format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
Mask masks the given error with the given format string and arguments (like
|
||||||
|
fmt.Sprintf), returning a new error that maintains the error stack, but
|
||||||
|
hides the underlying error type. The error string still contains the full
|
||||||
|
annotations. If you want to hide the annotations, call Wrap.
|
||||||
|
|
||||||
|
|
||||||
|
## func New
|
||||||
|
``` go
|
||||||
|
func New(message string) error
|
||||||
|
```
|
||||||
|
New is a drop in replacement for the standard libary errors module that records
|
||||||
|
the location that the error is created.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
return errors.New("validation failed")
|
||||||
|
|
||||||
|
|
||||||
|
## func NewAlreadyExists
|
||||||
|
``` go
|
||||||
|
func NewAlreadyExists(err error, msg string) error
|
||||||
|
```
|
||||||
|
NewAlreadyExists returns an error which wraps err and satisfies
|
||||||
|
IsAlreadyExists().
|
||||||
|
|
||||||
|
|
||||||
|
## func NewNotFound
|
||||||
|
``` go
|
||||||
|
func NewNotFound(err error, msg string) error
|
||||||
|
```
|
||||||
|
NewNotFound returns an error which wraps err that satisfies
|
||||||
|
IsNotFound().
|
||||||
|
|
||||||
|
|
||||||
|
## func NewNotImplemented
|
||||||
|
``` go
|
||||||
|
func NewNotImplemented(err error, msg string) error
|
||||||
|
```
|
||||||
|
NewNotImplemented returns an error which wraps err and satisfies
|
||||||
|
IsNotImplemented().
|
||||||
|
|
||||||
|
|
||||||
|
## func NewNotSupported
|
||||||
|
``` go
|
||||||
|
func NewNotSupported(err error, msg string) error
|
||||||
|
```
|
||||||
|
NewNotSupported returns an error which wraps err and satisfies
|
||||||
|
IsNotSupported().
|
||||||
|
|
||||||
|
|
||||||
|
## func NewNotValid
|
||||||
|
``` go
|
||||||
|
func NewNotValid(err error, msg string) error
|
||||||
|
```
|
||||||
|
NewNotValid returns an error which wraps err and satisfies IsNotValid().
|
||||||
|
|
||||||
|
|
||||||
|
## func NewUnauthorized
|
||||||
|
``` go
|
||||||
|
func NewUnauthorized(err error, msg string) error
|
||||||
|
```
|
||||||
|
NewUnauthorized returns an error which wraps err and satisfies
|
||||||
|
IsUnauthorized().
|
||||||
|
|
||||||
|
|
||||||
|
## func NotFoundf
|
||||||
|
``` go
|
||||||
|
func NotFoundf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
NotFoundf returns an error which satisfies IsNotFound().
|
||||||
|
|
||||||
|
|
||||||
|
## func NotImplementedf
|
||||||
|
``` go
|
||||||
|
func NotImplementedf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
NotImplementedf returns an error which satisfies IsNotImplemented().
|
||||||
|
|
||||||
|
|
||||||
|
## func NotSupportedf
|
||||||
|
``` go
|
||||||
|
func NotSupportedf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
NotSupportedf returns an error which satisfies IsNotSupported().
|
||||||
|
|
||||||
|
|
||||||
|
## func NotValidf
|
||||||
|
``` go
|
||||||
|
func NotValidf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
NotValidf returns an error which satisfies IsNotValid().
|
||||||
|
|
||||||
|
|
||||||
|
## func Trace
|
||||||
|
``` go
|
||||||
|
func Trace(other error) error
|
||||||
|
```
|
||||||
|
Trace adds the location of the Trace call to the stack. The Cause of the
|
||||||
|
resulting error is the same as the error parameter. If the other error is
|
||||||
|
nil, the result will be nil.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## func Unauthorizedf
|
||||||
|
``` go
|
||||||
|
func Unauthorizedf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
Unauthorizedf returns an error which satisfies IsUnauthorized().
|
||||||
|
|
||||||
|
|
||||||
|
## func Forbiddenf
|
||||||
|
``` go
|
||||||
|
func Forbiddenf(format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
Forbiddenf returns an error which satisfies IsForbidden().
|
||||||
|
|
||||||
|
|
||||||
|
## func Wrap
|
||||||
|
``` go
|
||||||
|
func Wrap(other, newDescriptive error) error
|
||||||
|
```
|
||||||
|
Wrap changes the Cause of the error. The location of the Wrap call is also
|
||||||
|
stored in the error stack.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
newErr := &packageError{"more context", private_value}
|
||||||
|
return errors.Wrap(err, newErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## func Wrapf
|
||||||
|
``` go
|
||||||
|
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error
|
||||||
|
```
|
||||||
|
Wrapf changes the Cause of the error, and adds an annotation. The location
|
||||||
|
of the Wrap call is also stored in the error stack.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## type Err
|
||||||
|
``` go
|
||||||
|
type Err struct {
|
||||||
|
// contains filtered or unexported fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Err holds a description of an error along with information about
|
||||||
|
where the error was created.
|
||||||
|
|
||||||
|
It may be embedded in custom error types to add extra information that
|
||||||
|
this errors package can understand.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func NewErr
|
||||||
|
``` go
|
||||||
|
func NewErr(format string, args ...interface{}) Err
|
||||||
|
```
|
||||||
|
NewErr is used to return an Err for the purpose of embedding in other
|
||||||
|
structures. The location is not specified, and needs to be set with a call
|
||||||
|
to SetLocation.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
|
||||||
|
type FooError struct {
|
||||||
|
errors.Err
|
||||||
|
code int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooError(code int) error {
|
||||||
|
err := &FooError{errors.NewErr("foo"), code}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func (\*Err) Cause
|
||||||
|
``` go
|
||||||
|
func (e *Err) Cause() error
|
||||||
|
```
|
||||||
|
The Cause of an error is the most recent error in the error stack that
|
||||||
|
meets one of these criteria: the original error that was raised; the new
|
||||||
|
error that was passed into the Wrap function; the most recently masked
|
||||||
|
error; or nil if the error itself is considered the Cause. Normally this
|
||||||
|
method is not invoked directly, but instead through the Cause stand alone
|
||||||
|
function.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func (\*Err) Error
|
||||||
|
``` go
|
||||||
|
func (e *Err) Error() string
|
||||||
|
```
|
||||||
|
Error implements error.Error.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func (\*Err) Location
|
||||||
|
``` go
|
||||||
|
func (e *Err) Location() (filename string, line int)
|
||||||
|
```
|
||||||
|
Location is the file and line of where the error was most recently
|
||||||
|
created or annotated.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func (\*Err) Message
|
||||||
|
``` go
|
||||||
|
func (e *Err) Message() string
|
||||||
|
```
|
||||||
|
Message returns the message stored with the most recent location. This is
|
||||||
|
the empty string if the most recent call was Trace, or the message stored
|
||||||
|
with Annotate or Mask.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func (\*Err) SetLocation
|
||||||
|
``` go
|
||||||
|
func (e *Err) SetLocation(callDepth int)
|
||||||
|
```
|
||||||
|
SetLocation records the source location of the error at callDepth stack
|
||||||
|
frames above the call.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func (\*Err) StackTrace
|
||||||
|
``` go
|
||||||
|
func (e *Err) StackTrace() []string
|
||||||
|
```
|
||||||
|
StackTrace returns one string for each location recorded in the stack of
|
||||||
|
errors. The first value is the originating error, with a line for each
|
||||||
|
other annotation or tracing of the error.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### func (\*Err) Underlying
|
||||||
|
``` go
|
||||||
|
func (e *Err) Underlying() error
|
||||||
|
```
|
||||||
|
Underlying returns the previous error in the error stack, if any. A client
|
||||||
|
should not ever really call this method. It is used to build the error
|
||||||
|
stack and should not be introspected by client calls. Or more
|
||||||
|
specifically, clients should not depend on anything but the `Cause` of an
|
||||||
|
error.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- - -
|
||||||
|
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)
|
81
vendor/github.com/juju/errors/doc.go
generated
vendored
Normal file
81
vendor/github.com/juju/errors/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2013, 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
/*
|
||||||
|
[godoc-link-here]
|
||||||
|
|
||||||
|
The juju/errors provides an easy way to annotate errors without losing the
|
||||||
|
orginal error context.
|
||||||
|
|
||||||
|
The exported `New` and `Errorf` functions are designed to replace the
|
||||||
|
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
|
||||||
|
error is there, but the package also records the location at which the error
|
||||||
|
was created.
|
||||||
|
|
||||||
|
A primary use case for this library is to add extra context any time an
|
||||||
|
error is returned from a function.
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
This instead becomes:
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Trace(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
which just records the file and line number of the Trace call, or
|
||||||
|
|
||||||
|
if err := SomeFunc(); err != nil {
|
||||||
|
return errors.Annotate(err, "more context")
|
||||||
|
}
|
||||||
|
|
||||||
|
which also adds an annotation to the error.
|
||||||
|
|
||||||
|
When you want to check to see if an error is of a particular type, a helper
|
||||||
|
function is normally exported by the package that returned the error, like the
|
||||||
|
`os` package does. The underlying cause of the error is available using the
|
||||||
|
`Cause` function.
|
||||||
|
|
||||||
|
os.IsNotExist(errors.Cause(err))
|
||||||
|
|
||||||
|
The result of the `Error()` call on an annotated error is the annotations joined
|
||||||
|
with colons, then the result of the `Error()` method for the underlying error
|
||||||
|
that was the cause.
|
||||||
|
|
||||||
|
err := errors.Errorf("original")
|
||||||
|
err = errors.Annotatef(err, "context")
|
||||||
|
err = errors.Annotatef(err, "more context")
|
||||||
|
err.Error() -> "more context: context: original"
|
||||||
|
|
||||||
|
Obviously recording the file, line and functions is not very useful if you
|
||||||
|
cannot get them back out again.
|
||||||
|
|
||||||
|
errors.ErrorStack(err)
|
||||||
|
|
||||||
|
will return something like:
|
||||||
|
|
||||||
|
first error
|
||||||
|
github.com/juju/errors/annotation_test.go:193:
|
||||||
|
github.com/juju/errors/annotation_test.go:194: annotation
|
||||||
|
github.com/juju/errors/annotation_test.go:195:
|
||||||
|
github.com/juju/errors/annotation_test.go:196: more context
|
||||||
|
github.com/juju/errors/annotation_test.go:197:
|
||||||
|
|
||||||
|
The first error was generated by an external system, so there was no location
|
||||||
|
associated. The second, fourth, and last lines were generated with Trace calls,
|
||||||
|
and the other two through Annotate.
|
||||||
|
|
||||||
|
Sometimes when responding to an error you want to return a more specific error
|
||||||
|
for the situation.
|
||||||
|
|
||||||
|
if err := FindField(field); err != nil {
|
||||||
|
return errors.Wrap(err, errors.NotFoundf(field))
|
||||||
|
}
|
||||||
|
|
||||||
|
This returns an error where the complete error stack is still available, and
|
||||||
|
`errors.Cause()` will return the `NotFound` error.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package errors
|
172
vendor/github.com/juju/errors/error.go
generated
vendored
Normal file
172
vendor/github.com/juju/errors/error.go
generated
vendored
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
// Copyright 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Err holds a description of an error along with information about
|
||||||
|
// where the error was created.
|
||||||
|
//
|
||||||
|
// It may be embedded in custom error types to add extra information that
|
||||||
|
// this errors package can understand.
|
||||||
|
type Err struct {
|
||||||
|
// message holds an annotation of the error.
|
||||||
|
message string
|
||||||
|
|
||||||
|
// cause holds the cause of the error as returned
|
||||||
|
// by the Cause method.
|
||||||
|
cause error
|
||||||
|
|
||||||
|
// previous holds the previous error in the error stack, if any.
|
||||||
|
previous error
|
||||||
|
|
||||||
|
// file and line hold the source code location where the error was
|
||||||
|
// created.
|
||||||
|
file string
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErr is used to return an Err for the purpose of embedding in other
|
||||||
|
// structures. The location is not specified, and needs to be set with a call
|
||||||
|
// to SetLocation.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// type FooError struct {
|
||||||
|
// errors.Err
|
||||||
|
// code int
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func NewFooError(code int) error {
|
||||||
|
// err := &FooError{errors.NewErr("foo"), code}
|
||||||
|
// err.SetLocation(1)
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
func NewErr(format string, args ...interface{}) Err {
|
||||||
|
return Err{
|
||||||
|
message: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrWithCause is used to return an Err with case by other error for the purpose of embedding in other
|
||||||
|
// structures. The location is not specified, and needs to be set with a call
|
||||||
|
// to SetLocation.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// type FooError struct {
|
||||||
|
// errors.Err
|
||||||
|
// code int
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// func (e *FooError) Annotate(format string, args ...interface{}) error {
|
||||||
|
// err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
|
||||||
|
// err.SetLocation(1)
|
||||||
|
// return err
|
||||||
|
// })
|
||||||
|
func NewErrWithCause(other error, format string, args ...interface{}) Err {
|
||||||
|
return Err{
|
||||||
|
message: fmt.Sprintf(format, args...),
|
||||||
|
cause: Cause(other),
|
||||||
|
previous: other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location is the file and line of where the error was most recently
|
||||||
|
// created or annotated.
|
||||||
|
func (e *Err) Location() (filename string, line int) {
|
||||||
|
return e.file, e.line
|
||||||
|
}
|
||||||
|
|
||||||
|
// Underlying returns the previous error in the error stack, if any. A client
|
||||||
|
// should not ever really call this method. It is used to build the error
|
||||||
|
// stack and should not be introspected by client calls. Or more
|
||||||
|
// specifically, clients should not depend on anything but the `Cause` of an
|
||||||
|
// error.
|
||||||
|
func (e *Err) Underlying() error {
|
||||||
|
return e.previous
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Cause of an error is the most recent error in the error stack that
|
||||||
|
// meets one of these criteria: the original error that was raised; the new
|
||||||
|
// error that was passed into the Wrap function; the most recently masked
|
||||||
|
// error; or nil if the error itself is considered the Cause. Normally this
|
||||||
|
// method is not invoked directly, but instead through the Cause stand alone
|
||||||
|
// function.
|
||||||
|
func (e *Err) Cause() error {
|
||||||
|
return e.cause
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message returns the message stored with the most recent location. This is
|
||||||
|
// the empty string if the most recent call was Trace, or the message stored
|
||||||
|
// with Annotate or Mask.
|
||||||
|
func (e *Err) Message() string {
|
||||||
|
return e.message
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements error.Error.
|
||||||
|
func (e *Err) Error() string {
|
||||||
|
// We want to walk up the stack of errors showing the annotations
|
||||||
|
// as long as the cause is the same.
|
||||||
|
err := e.previous
|
||||||
|
if !sameError(Cause(err), e.cause) && e.cause != nil {
|
||||||
|
err = e.cause
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
return e.message
|
||||||
|
case e.message == "":
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s: %v", e.message, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format implements fmt.Formatter
|
||||||
|
// When printing errors with %+v it also prints the stack trace.
|
||||||
|
// %#v unsurprisingly will print the real underlying type.
|
||||||
|
func (e *Err) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
fmt.Fprintf(s, "%s", ErrorStack(e))
|
||||||
|
return
|
||||||
|
case s.Flag('#'):
|
||||||
|
// avoid infinite recursion by wrapping e into a type
|
||||||
|
// that doesn't implement Formatter.
|
||||||
|
fmt.Fprintf(s, "%#v", (*unformatter)(e))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
fmt.Fprintf(s, "%s", e.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper for Format
|
||||||
|
type unformatter Err
|
||||||
|
|
||||||
|
func (unformatter) Format() { /* break the fmt.Formatter interface */ }
|
||||||
|
|
||||||
|
// SetLocation records the source location of the error at callDepth stack
|
||||||
|
// frames above the call.
|
||||||
|
func (e *Err) SetLocation(callDepth int) {
|
||||||
|
_, file, line, _ := runtime.Caller(callDepth + 1)
|
||||||
|
e.file = trimGoPath(file)
|
||||||
|
e.line = line
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackTrace returns one string for each location recorded in the stack of
|
||||||
|
// errors. The first value is the originating error, with a line for each
|
||||||
|
// other annotation or tracing of the error.
|
||||||
|
func (e *Err) StackTrace() []string {
|
||||||
|
return errorStack(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ideally we'd have a way to check identity, but deep equals will do.
|
||||||
|
func sameError(e1, e2 error) bool {
|
||||||
|
return reflect.DeepEqual(e1, e2)
|
||||||
|
}
|
178
vendor/github.com/juju/errors/error_test.go
generated
vendored
Normal file
178
vendor/github.com/juju/errors/error_test.go
generated
vendored
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
// Copyright 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
jc "github.com/juju/testing/checkers"
|
||||||
|
gc "gopkg.in/check.v1"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type errorsSuite struct{}
|
||||||
|
|
||||||
|
var _ = gc.Suite(&errorsSuite{})
|
||||||
|
|
||||||
|
var someErr = errors.New("some error") //err varSomeErr
|
||||||
|
|
||||||
|
func (*errorsSuite) TestErrorString(c *gc.C) {
|
||||||
|
for i, test := range []struct {
|
||||||
|
message string
|
||||||
|
generator func() error
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
message: "uncomparable errors",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.Annotatef(newNonComparableError("uncomparable"), "annotation")
|
||||||
|
return errors.Annotatef(err, "another")
|
||||||
|
},
|
||||||
|
expected: "another: annotation: uncomparable",
|
||||||
|
}, {
|
||||||
|
message: "Errorf",
|
||||||
|
generator: func() error {
|
||||||
|
return errors.Errorf("first error")
|
||||||
|
},
|
||||||
|
expected: "first error",
|
||||||
|
}, {
|
||||||
|
message: "annotated error",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.Errorf("first error")
|
||||||
|
return errors.Annotatef(err, "annotation")
|
||||||
|
},
|
||||||
|
expected: "annotation: first error",
|
||||||
|
}, {
|
||||||
|
message: "test annotation format",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.Errorf("first %s", "error")
|
||||||
|
return errors.Annotatef(err, "%s", "annotation")
|
||||||
|
},
|
||||||
|
expected: "annotation: first error",
|
||||||
|
}, {
|
||||||
|
message: "wrapped error",
|
||||||
|
generator: func() error {
|
||||||
|
err := newError("first error")
|
||||||
|
return errors.Wrap(err, newError("detailed error"))
|
||||||
|
},
|
||||||
|
expected: "detailed error",
|
||||||
|
}, {
|
||||||
|
message: "wrapped annotated error",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.Errorf("first error")
|
||||||
|
err = errors.Annotatef(err, "annotated")
|
||||||
|
return errors.Wrap(err, fmt.Errorf("detailed error"))
|
||||||
|
},
|
||||||
|
expected: "detailed error",
|
||||||
|
}, {
|
||||||
|
message: "annotated wrapped error",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.Errorf("first error")
|
||||||
|
err = errors.Wrap(err, fmt.Errorf("detailed error"))
|
||||||
|
return errors.Annotatef(err, "annotated")
|
||||||
|
},
|
||||||
|
expected: "annotated: detailed error",
|
||||||
|
}, {
|
||||||
|
message: "traced, and annotated",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.New("first error")
|
||||||
|
err = errors.Trace(err)
|
||||||
|
err = errors.Annotate(err, "some context")
|
||||||
|
err = errors.Trace(err)
|
||||||
|
err = errors.Annotate(err, "more context")
|
||||||
|
return errors.Trace(err)
|
||||||
|
},
|
||||||
|
expected: "more context: some context: first error",
|
||||||
|
}, {
|
||||||
|
message: "traced, and annotated, masked and annotated",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.New("first error")
|
||||||
|
err = errors.Trace(err)
|
||||||
|
err = errors.Annotate(err, "some context")
|
||||||
|
err = errors.Maskf(err, "masked")
|
||||||
|
err = errors.Annotate(err, "more context")
|
||||||
|
return errors.Trace(err)
|
||||||
|
},
|
||||||
|
expected: "more context: masked: some context: first error",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
c.Logf("%v: %s", i, test.message)
|
||||||
|
err := test.generator()
|
||||||
|
ok := c.Check(err.Error(), gc.Equals, test.expected)
|
||||||
|
if !ok {
|
||||||
|
c.Logf("%#v", test.generator())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type embed struct {
|
||||||
|
errors.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEmbed(format string, args ...interface{}) *embed {
|
||||||
|
err := &embed{errors.NewErr(format, args...)}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*errorsSuite) TestNewErr(c *gc.C) {
|
||||||
|
if runtime.Compiler == "gccgo" {
|
||||||
|
c.Skip("gccgo can't determine the location")
|
||||||
|
}
|
||||||
|
err := newEmbed("testing %d", 42) //err embedErr
|
||||||
|
c.Assert(err.Error(), gc.Equals, "testing 42")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["embedErr"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEmbedWithCause(other error, format string, args ...interface{}) *embed {
|
||||||
|
err := &embed{errors.NewErrWithCause(other, format, args...)}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*errorsSuite) TestNewErrWithCause(c *gc.C) {
|
||||||
|
if runtime.Compiler == "gccgo" {
|
||||||
|
c.Skip("gccgo can't determine the location")
|
||||||
|
}
|
||||||
|
causeErr := fmt.Errorf("external error")
|
||||||
|
err := newEmbedWithCause(causeErr, "testing %d", 43) //err embedCause
|
||||||
|
c.Assert(err.Error(), gc.Equals, "testing 43: external error")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, causeErr)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["embedCause"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ error = (*embed)(nil)
|
||||||
|
|
||||||
|
// This is an uncomparable error type, as it is a struct that supports the
|
||||||
|
// error interface (as opposed to a pointer type).
|
||||||
|
type error_ struct {
|
||||||
|
info string
|
||||||
|
slice []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a non-comparable error
|
||||||
|
func newNonComparableError(message string) error {
|
||||||
|
return error_{info: message}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e error_) Error() string {
|
||||||
|
return e.info
|
||||||
|
}
|
||||||
|
|
||||||
|
func newError(message string) error {
|
||||||
|
return testError{message}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The testError is a value type error for ease of seeing results
|
||||||
|
// when the test fails.
|
||||||
|
type testError struct {
|
||||||
|
message string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e testError) Error() string {
|
||||||
|
return e.message
|
||||||
|
}
|
309
vendor/github.com/juju/errors/errortypes.go
generated
vendored
Normal file
309
vendor/github.com/juju/errors/errortypes.go
generated
vendored
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
// Copyright 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// wrap is a helper to construct an *wrapper.
|
||||||
|
func wrap(err error, format, suffix string, args ...interface{}) Err {
|
||||||
|
newErr := Err{
|
||||||
|
message: fmt.Sprintf(format+suffix, args...),
|
||||||
|
previous: err,
|
||||||
|
}
|
||||||
|
newErr.SetLocation(2)
|
||||||
|
return newErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// notFound represents an error when something has not been found.
|
||||||
|
type notFound struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotFoundf returns an error which satisfies IsNotFound().
|
||||||
|
func NotFoundf(format string, args ...interface{}) error {
|
||||||
|
return ¬Found{wrap(nil, format, " not found", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotFound returns an error which wraps err that satisfies
|
||||||
|
// IsNotFound().
|
||||||
|
func NewNotFound(err error, msg string) error {
|
||||||
|
return ¬Found{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotFound reports whether err was created with NotFoundf() or
|
||||||
|
// NewNotFound().
|
||||||
|
func IsNotFound(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*notFound)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// userNotFound represents an error when an inexistent user is looked up.
|
||||||
|
type userNotFound struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserNotFoundf returns an error which satisfies IsUserNotFound().
|
||||||
|
func UserNotFoundf(format string, args ...interface{}) error {
|
||||||
|
return &userNotFound{wrap(nil, format, " user not found", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUserNotFound returns an error which wraps err and satisfies
|
||||||
|
// IsUserNotFound().
|
||||||
|
func NewUserNotFound(err error, msg string) error {
|
||||||
|
return &userNotFound{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUserNotFound reports whether err was created with UserNotFoundf() or
|
||||||
|
// NewUserNotFound().
|
||||||
|
func IsUserNotFound(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*userNotFound)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// unauthorized represents an error when an operation is unauthorized.
|
||||||
|
type unauthorized struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unauthorizedf returns an error which satisfies IsUnauthorized().
|
||||||
|
func Unauthorizedf(format string, args ...interface{}) error {
|
||||||
|
return &unauthorized{wrap(nil, format, "", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUnauthorized returns an error which wraps err and satisfies
|
||||||
|
// IsUnauthorized().
|
||||||
|
func NewUnauthorized(err error, msg string) error {
|
||||||
|
return &unauthorized{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUnauthorized reports whether err was created with Unauthorizedf() or
|
||||||
|
// NewUnauthorized().
|
||||||
|
func IsUnauthorized(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*unauthorized)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// notImplemented represents an error when something is not
|
||||||
|
// implemented.
|
||||||
|
type notImplemented struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotImplementedf returns an error which satisfies IsNotImplemented().
|
||||||
|
func NotImplementedf(format string, args ...interface{}) error {
|
||||||
|
return ¬Implemented{wrap(nil, format, " not implemented", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotImplemented returns an error which wraps err and satisfies
|
||||||
|
// IsNotImplemented().
|
||||||
|
func NewNotImplemented(err error, msg string) error {
|
||||||
|
return ¬Implemented{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotImplemented reports whether err was created with
|
||||||
|
// NotImplementedf() or NewNotImplemented().
|
||||||
|
func IsNotImplemented(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*notImplemented)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// alreadyExists represents and error when something already exists.
|
||||||
|
type alreadyExists struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlreadyExistsf returns an error which satisfies IsAlreadyExists().
|
||||||
|
func AlreadyExistsf(format string, args ...interface{}) error {
|
||||||
|
return &alreadyExists{wrap(nil, format, " already exists", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAlreadyExists returns an error which wraps err and satisfies
|
||||||
|
// IsAlreadyExists().
|
||||||
|
func NewAlreadyExists(err error, msg string) error {
|
||||||
|
return &alreadyExists{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyExists reports whether the error was created with
|
||||||
|
// AlreadyExistsf() or NewAlreadyExists().
|
||||||
|
func IsAlreadyExists(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*alreadyExists)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// notSupported represents an error when something is not supported.
|
||||||
|
type notSupported struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotSupportedf returns an error which satisfies IsNotSupported().
|
||||||
|
func NotSupportedf(format string, args ...interface{}) error {
|
||||||
|
return ¬Supported{wrap(nil, format, " not supported", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotSupported returns an error which wraps err and satisfies
|
||||||
|
// IsNotSupported().
|
||||||
|
func NewNotSupported(err error, msg string) error {
|
||||||
|
return ¬Supported{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotSupported reports whether the error was created with
|
||||||
|
// NotSupportedf() or NewNotSupported().
|
||||||
|
func IsNotSupported(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*notSupported)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// notValid represents an error when something is not valid.
|
||||||
|
type notValid struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotValidf returns an error which satisfies IsNotValid().
|
||||||
|
func NotValidf(format string, args ...interface{}) error {
|
||||||
|
return ¬Valid{wrap(nil, format, " not valid", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotValid returns an error which wraps err and satisfies IsNotValid().
|
||||||
|
func NewNotValid(err error, msg string) error {
|
||||||
|
return ¬Valid{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotValid reports whether the error was created with NotValidf() or
|
||||||
|
// NewNotValid().
|
||||||
|
func IsNotValid(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*notValid)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// notProvisioned represents an error when something is not yet provisioned.
|
||||||
|
type notProvisioned struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotProvisionedf returns an error which satisfies IsNotProvisioned().
|
||||||
|
func NotProvisionedf(format string, args ...interface{}) error {
|
||||||
|
return ¬Provisioned{wrap(nil, format, " not provisioned", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotProvisioned returns an error which wraps err that satisfies
|
||||||
|
// IsNotProvisioned().
|
||||||
|
func NewNotProvisioned(err error, msg string) error {
|
||||||
|
return ¬Provisioned{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotProvisioned reports whether err was created with NotProvisionedf() or
|
||||||
|
// NewNotProvisioned().
|
||||||
|
func IsNotProvisioned(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*notProvisioned)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// notAssigned represents an error when something is not yet assigned to
|
||||||
|
// something else.
|
||||||
|
type notAssigned struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotAssignedf returns an error which satisfies IsNotAssigned().
|
||||||
|
func NotAssignedf(format string, args ...interface{}) error {
|
||||||
|
return ¬Assigned{wrap(nil, format, " not assigned", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotAssigned returns an error which wraps err that satisfies
|
||||||
|
// IsNotAssigned().
|
||||||
|
func NewNotAssigned(err error, msg string) error {
|
||||||
|
return ¬Assigned{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotAssigned reports whether err was created with NotAssignedf() or
|
||||||
|
// NewNotAssigned().
|
||||||
|
func IsNotAssigned(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*notAssigned)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// badRequest represents an error when a request has bad parameters.
|
||||||
|
type badRequest struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// BadRequestf returns an error which satisfies IsBadRequest().
|
||||||
|
func BadRequestf(format string, args ...interface{}) error {
|
||||||
|
return &badRequest{wrap(nil, format, "", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBadRequest returns an error which wraps err that satisfies
|
||||||
|
// IsBadRequest().
|
||||||
|
func NewBadRequest(err error, msg string) error {
|
||||||
|
return &badRequest{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsBadRequest reports whether err was created with BadRequestf() or
|
||||||
|
// NewBadRequest().
|
||||||
|
func IsBadRequest(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*badRequest)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// methodNotAllowed represents an error when an HTTP request
|
||||||
|
// is made with an inappropriate method.
|
||||||
|
type methodNotAllowed struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MethodNotAllowedf returns an error which satisfies IsMethodNotAllowed().
|
||||||
|
func MethodNotAllowedf(format string, args ...interface{}) error {
|
||||||
|
return &methodNotAllowed{wrap(nil, format, "", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMethodNotAllowed returns an error which wraps err that satisfies
|
||||||
|
// IsMethodNotAllowed().
|
||||||
|
func NewMethodNotAllowed(err error, msg string) error {
|
||||||
|
return &methodNotAllowed{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMethodNotAllowed reports whether err was created with MethodNotAllowedf() or
|
||||||
|
// NewMethodNotAllowed().
|
||||||
|
func IsMethodNotAllowed(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*methodNotAllowed)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// forbidden represents an error when a request cannot be completed because of
|
||||||
|
// missing privileges
|
||||||
|
type forbidden struct {
|
||||||
|
Err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forbiddenf returns an error which satistifes IsForbidden()
|
||||||
|
func Forbiddenf(format string, args ...interface{}) error {
|
||||||
|
return &forbidden{wrap(nil, format, "", args...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewForbidden returns an error which wraps err that satisfies
|
||||||
|
// IsForbidden().
|
||||||
|
func NewForbidden(err error, msg string) error {
|
||||||
|
return &forbidden{wrap(err, msg, "")}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForbidden reports whether err was created with Forbiddenf() or
|
||||||
|
// NewForbidden().
|
||||||
|
func IsForbidden(err error) bool {
|
||||||
|
err = Cause(err)
|
||||||
|
_, ok := err.(*forbidden)
|
||||||
|
return ok
|
||||||
|
}
|
174
vendor/github.com/juju/errors/errortypes_test.go
generated
vendored
Normal file
174
vendor/github.com/juju/errors/errortypes_test.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
// Copyright 2013, 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
stderrors "errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
jc "github.com/juju/testing/checkers"
|
||||||
|
gc "gopkg.in/check.v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errorInfo holds information about a single error type: a satisfier
|
||||||
|
// function, wrapping and variable arguments constructors and message
|
||||||
|
// suffix.
|
||||||
|
type errorInfo struct {
|
||||||
|
satisfier func(error) bool
|
||||||
|
argsConstructor func(string, ...interface{}) error
|
||||||
|
wrapConstructor func(error, string) error
|
||||||
|
suffix string
|
||||||
|
}
|
||||||
|
|
||||||
|
// allErrors holds information for all defined errors. When adding new
|
||||||
|
// errors, add them here as well to include them in tests.
|
||||||
|
var allErrors = []*errorInfo{
|
||||||
|
{errors.IsNotFound, errors.NotFoundf, errors.NewNotFound, " not found"},
|
||||||
|
{errors.IsUserNotFound, errors.UserNotFoundf, errors.NewUserNotFound, " user not found"},
|
||||||
|
{errors.IsUnauthorized, errors.Unauthorizedf, errors.NewUnauthorized, ""},
|
||||||
|
{errors.IsNotImplemented, errors.NotImplementedf, errors.NewNotImplemented, " not implemented"},
|
||||||
|
{errors.IsAlreadyExists, errors.AlreadyExistsf, errors.NewAlreadyExists, " already exists"},
|
||||||
|
{errors.IsNotSupported, errors.NotSupportedf, errors.NewNotSupported, " not supported"},
|
||||||
|
{errors.IsNotValid, errors.NotValidf, errors.NewNotValid, " not valid"},
|
||||||
|
{errors.IsNotProvisioned, errors.NotProvisionedf, errors.NewNotProvisioned, " not provisioned"},
|
||||||
|
{errors.IsNotAssigned, errors.NotAssignedf, errors.NewNotAssigned, " not assigned"},
|
||||||
|
{errors.IsMethodNotAllowed, errors.MethodNotAllowedf, errors.NewMethodNotAllowed, ""},
|
||||||
|
{errors.IsBadRequest, errors.BadRequestf, errors.NewBadRequest, ""},
|
||||||
|
{errors.IsForbidden, errors.Forbiddenf, errors.NewForbidden, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorTypeSuite struct{}
|
||||||
|
|
||||||
|
var _ = gc.Suite(&errorTypeSuite{})
|
||||||
|
|
||||||
|
func (t *errorInfo) satisfierName() string {
|
||||||
|
value := reflect.ValueOf(t.satisfier)
|
||||||
|
f := runtime.FuncForPC(value.Pointer())
|
||||||
|
return f.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *errorInfo) equal(t0 *errorInfo) bool {
|
||||||
|
if t0 == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return t.satisfierName() == t0.satisfierName()
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorTest struct {
|
||||||
|
err error
|
||||||
|
message string
|
||||||
|
errInfo *errorInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func deferredAnnotatef(err error, format string, args ...interface{}) error {
|
||||||
|
errors.DeferredAnnotatef(&err, format, args...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustSatisfy(c *gc.C, err error, errInfo *errorInfo) {
|
||||||
|
if errInfo != nil {
|
||||||
|
msg := fmt.Sprintf("%#v must satisfy %v", err, errInfo.satisfierName())
|
||||||
|
c.Check(err, jc.Satisfies, errInfo.satisfier, gc.Commentf(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustNotSatisfy(c *gc.C, err error, errInfo *errorInfo) {
|
||||||
|
if errInfo != nil {
|
||||||
|
msg := fmt.Sprintf("%#v must not satisfy %v", err, errInfo.satisfierName())
|
||||||
|
c.Check(err, gc.Not(jc.Satisfies), errInfo.satisfier, gc.Commentf(msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErrorMatches(c *gc.C, err error, message string, errInfo *errorInfo) {
|
||||||
|
if message == "<nil>" {
|
||||||
|
c.Check(err, gc.IsNil)
|
||||||
|
c.Check(errInfo, gc.IsNil)
|
||||||
|
} else {
|
||||||
|
c.Check(err, gc.ErrorMatches, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runErrorTests(c *gc.C, errorTests []errorTest, checkMustSatisfy bool) {
|
||||||
|
for i, t := range errorTests {
|
||||||
|
c.Logf("test %d: %T: %v", i, t.err, t.err)
|
||||||
|
checkErrorMatches(c, t.err, t.message, t.errInfo)
|
||||||
|
if checkMustSatisfy {
|
||||||
|
mustSatisfy(c, t.err, t.errInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check all other satisfiers to make sure none match.
|
||||||
|
for _, otherErrInfo := range allErrors {
|
||||||
|
if checkMustSatisfy && otherErrInfo.equal(t.errInfo) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mustNotSatisfy(c, t.err, otherErrInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*errorTypeSuite) TestDeferredAnnotatef(c *gc.C) {
|
||||||
|
// Ensure DeferredAnnotatef annotates the errors.
|
||||||
|
errorTests := []errorTest{}
|
||||||
|
for _, errInfo := range allErrors {
|
||||||
|
errorTests = append(errorTests, []errorTest{{
|
||||||
|
deferredAnnotatef(nil, "comment"),
|
||||||
|
"<nil>",
|
||||||
|
nil,
|
||||||
|
}, {
|
||||||
|
deferredAnnotatef(stderrors.New("blast"), "comment"),
|
||||||
|
"comment: blast",
|
||||||
|
nil,
|
||||||
|
}, {
|
||||||
|
deferredAnnotatef(errInfo.argsConstructor("foo %d", 42), "comment %d", 69),
|
||||||
|
"comment 69: foo 42" + errInfo.suffix,
|
||||||
|
errInfo,
|
||||||
|
}, {
|
||||||
|
deferredAnnotatef(errInfo.argsConstructor(""), "comment"),
|
||||||
|
"comment: " + errInfo.suffix,
|
||||||
|
errInfo,
|
||||||
|
}, {
|
||||||
|
deferredAnnotatef(errInfo.wrapConstructor(stderrors.New("pow!"), "woo"), "comment"),
|
||||||
|
"comment: woo: pow!",
|
||||||
|
errInfo,
|
||||||
|
}}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
runErrorTests(c, errorTests, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*errorTypeSuite) TestAllErrors(c *gc.C) {
|
||||||
|
errorTests := []errorTest{}
|
||||||
|
for _, errInfo := range allErrors {
|
||||||
|
errorTests = append(errorTests, []errorTest{{
|
||||||
|
nil,
|
||||||
|
"<nil>",
|
||||||
|
nil,
|
||||||
|
}, {
|
||||||
|
errInfo.argsConstructor("foo %d", 42),
|
||||||
|
"foo 42" + errInfo.suffix,
|
||||||
|
errInfo,
|
||||||
|
}, {
|
||||||
|
errInfo.argsConstructor(""),
|
||||||
|
errInfo.suffix,
|
||||||
|
errInfo,
|
||||||
|
}, {
|
||||||
|
errInfo.wrapConstructor(stderrors.New("pow!"), "prefix"),
|
||||||
|
"prefix: pow!",
|
||||||
|
errInfo,
|
||||||
|
}, {
|
||||||
|
errInfo.wrapConstructor(stderrors.New("pow!"), ""),
|
||||||
|
"pow!",
|
||||||
|
errInfo,
|
||||||
|
}, {
|
||||||
|
errInfo.wrapConstructor(nil, "prefix"),
|
||||||
|
"prefix",
|
||||||
|
errInfo,
|
||||||
|
}}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
runErrorTests(c, errorTests, true)
|
||||||
|
}
|
23
vendor/github.com/juju/errors/example_test.go
generated
vendored
Normal file
23
vendor/github.com/juju/errors/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2013, 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleTrace() {
|
||||||
|
var err1 error = fmt.Errorf("something wicked this way comes")
|
||||||
|
var err2 error = nil
|
||||||
|
|
||||||
|
// Tracing a non nil error will return an error
|
||||||
|
fmt.Println(errors.Trace(err1))
|
||||||
|
// Tracing nil will return nil
|
||||||
|
fmt.Println(errors.Trace(err2))
|
||||||
|
|
||||||
|
// Output: something wicked this way comes
|
||||||
|
// <nil>
|
||||||
|
}
|
12
vendor/github.com/juju/errors/export_test.go
generated
vendored
Normal file
12
vendor/github.com/juju/errors/export_test.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// Copyright 2013, 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors
|
||||||
|
|
||||||
|
// Since variables are declared before the init block, in order to get the goPath
|
||||||
|
// we need to return it rather than just reference it.
|
||||||
|
func GoPath() string {
|
||||||
|
return goPath
|
||||||
|
}
|
||||||
|
|
||||||
|
var TrimGoPath = trimGoPath
|
330
vendor/github.com/juju/errors/functions.go
generated
vendored
Normal file
330
vendor/github.com/juju/errors/functions.go
generated
vendored
Normal file
|
@ -0,0 +1,330 @@
|
||||||
|
// Copyright 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New is a drop in replacement for the standard library errors module that records
|
||||||
|
// the location that the error is created.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// return errors.New("validation failed")
|
||||||
|
//
|
||||||
|
func New(message string) error {
|
||||||
|
err := &Err{message: message}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf creates a new annotated error and records the location that the
|
||||||
|
// error is created. This should be a drop in replacement for fmt.Errorf.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// return errors.Errorf("validation failed: %s", message)
|
||||||
|
//
|
||||||
|
func Errorf(format string, args ...interface{}) error {
|
||||||
|
err := &Err{message: fmt.Sprintf(format, args...)}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace adds the location of the Trace call to the stack. The Cause of the
|
||||||
|
// resulting error is the same as the error parameter. If the other error is
|
||||||
|
// nil, the result will be nil.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// if err := SomeFunc(); err != nil {
|
||||||
|
// return errors.Trace(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func Trace(other error) error {
|
||||||
|
if other == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := &Err{previous: other, cause: Cause(other)}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotate is used to add extra context to an existing error. The location of
|
||||||
|
// the Annotate call is recorded with the annotations. The file, line and
|
||||||
|
// function are also recorded.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// if err := SomeFunc(); err != nil {
|
||||||
|
// return errors.Annotate(err, "failed to frombulate")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func Annotate(other error, message string) error {
|
||||||
|
if other == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := &Err{
|
||||||
|
previous: other,
|
||||||
|
cause: Cause(other),
|
||||||
|
message: message,
|
||||||
|
}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Annotatef is used to add extra context to an existing error. The location of
|
||||||
|
// the Annotate call is recorded with the annotations. The file, line and
|
||||||
|
// function are also recorded.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// if err := SomeFunc(); err != nil {
|
||||||
|
// return errors.Annotatef(err, "failed to frombulate the %s", arg)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func Annotatef(other error, format string, args ...interface{}) error {
|
||||||
|
if other == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := &Err{
|
||||||
|
previous: other,
|
||||||
|
cause: Cause(other),
|
||||||
|
message: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeferredAnnotatef annotates the given error (when it is not nil) with the given
|
||||||
|
// format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
|
||||||
|
// does nothing. This method is used in a defer statement in order to annotate any
|
||||||
|
// resulting error with the same message.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
//
|
||||||
|
// defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
|
||||||
|
//
|
||||||
|
func DeferredAnnotatef(err *error, format string, args ...interface{}) {
|
||||||
|
if *err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
newErr := &Err{
|
||||||
|
message: fmt.Sprintf(format, args...),
|
||||||
|
cause: Cause(*err),
|
||||||
|
previous: *err,
|
||||||
|
}
|
||||||
|
newErr.SetLocation(1)
|
||||||
|
*err = newErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap changes the Cause of the error. The location of the Wrap call is also
|
||||||
|
// stored in the error stack.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// if err := SomeFunc(); err != nil {
|
||||||
|
// newErr := &packageError{"more context", private_value}
|
||||||
|
// return errors.Wrap(err, newErr)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func Wrap(other, newDescriptive error) error {
|
||||||
|
err := &Err{
|
||||||
|
previous: other,
|
||||||
|
cause: newDescriptive,
|
||||||
|
}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapf changes the Cause of the error, and adds an annotation. The location
|
||||||
|
// of the Wrap call is also stored in the error stack.
|
||||||
|
//
|
||||||
|
// For example:
|
||||||
|
// if err := SomeFunc(); err != nil {
|
||||||
|
// return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error {
|
||||||
|
err := &Err{
|
||||||
|
message: fmt.Sprintf(format, args...),
|
||||||
|
previous: other,
|
||||||
|
cause: newDescriptive,
|
||||||
|
}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask masks the given error with the given format string and arguments (like
|
||||||
|
// fmt.Sprintf), returning a new error that maintains the error stack, but
|
||||||
|
// hides the underlying error type. The error string still contains the full
|
||||||
|
// annotations. If you want to hide the annotations, call Wrap.
|
||||||
|
func Maskf(other error, format string, args ...interface{}) error {
|
||||||
|
if other == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := &Err{
|
||||||
|
message: fmt.Sprintf(format, args...),
|
||||||
|
previous: other,
|
||||||
|
}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask hides the underlying error type, and records the location of the masking.
|
||||||
|
func Mask(other error) error {
|
||||||
|
if other == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := &Err{
|
||||||
|
previous: other,
|
||||||
|
}
|
||||||
|
err.SetLocation(1)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cause returns the cause of the given error. This will be either the
|
||||||
|
// original error, or the result of a Wrap or Mask call.
|
||||||
|
//
|
||||||
|
// Cause is the usual way to diagnose errors that may have been wrapped by
|
||||||
|
// the other errors functions.
|
||||||
|
func Cause(err error) error {
|
||||||
|
var diag error
|
||||||
|
if err, ok := err.(causer); ok {
|
||||||
|
diag = err.Cause()
|
||||||
|
}
|
||||||
|
if diag != nil {
|
||||||
|
return diag
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type causer interface {
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrapper interface {
|
||||||
|
// Message returns the top level error message,
|
||||||
|
// not including the message from the Previous
|
||||||
|
// error.
|
||||||
|
Message() string
|
||||||
|
|
||||||
|
// Underlying returns the Previous error, or nil
|
||||||
|
// if there is none.
|
||||||
|
Underlying() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type locationer interface {
|
||||||
|
Location() (string, int)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ wrapper = (*Err)(nil)
|
||||||
|
_ locationer = (*Err)(nil)
|
||||||
|
_ causer = (*Err)(nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Details returns information about the stack of errors wrapped by err, in
|
||||||
|
// the format:
|
||||||
|
//
|
||||||
|
// [{filename:99: error one} {otherfile:55: cause of error one}]
|
||||||
|
//
|
||||||
|
// This is a terse alternative to ErrorStack as it returns a single line.
|
||||||
|
func Details(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
var s []byte
|
||||||
|
s = append(s, '[')
|
||||||
|
for {
|
||||||
|
s = append(s, '{')
|
||||||
|
if err, ok := err.(locationer); ok {
|
||||||
|
file, line := err.Location()
|
||||||
|
if file != "" {
|
||||||
|
s = append(s, fmt.Sprintf("%s:%d", file, line)...)
|
||||||
|
s = append(s, ": "...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cerr, ok := err.(wrapper); ok {
|
||||||
|
s = append(s, cerr.Message()...)
|
||||||
|
err = cerr.Underlying()
|
||||||
|
} else {
|
||||||
|
s = append(s, err.Error()...)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
s = append(s, '}')
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s = append(s, ' ')
|
||||||
|
}
|
||||||
|
s = append(s, ']')
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorStack returns a string representation of the annotated error. If the
|
||||||
|
// error passed as the parameter is not an annotated error, the result is
|
||||||
|
// simply the result of the Error() method on that error.
|
||||||
|
//
|
||||||
|
// If the error is an annotated error, a multi-line string is returned where
|
||||||
|
// each line represents one entry in the annotation stack. The full filename
|
||||||
|
// from the call stack is used in the output.
|
||||||
|
//
|
||||||
|
// first error
|
||||||
|
// github.com/juju/errors/annotation_test.go:193:
|
||||||
|
// github.com/juju/errors/annotation_test.go:194: annotation
|
||||||
|
// github.com/juju/errors/annotation_test.go:195:
|
||||||
|
// github.com/juju/errors/annotation_test.go:196: more context
|
||||||
|
// github.com/juju/errors/annotation_test.go:197:
|
||||||
|
func ErrorStack(err error) string {
|
||||||
|
return strings.Join(errorStack(err), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func errorStack(err error) []string {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want the first error first
|
||||||
|
var lines []string
|
||||||
|
for {
|
||||||
|
var buff []byte
|
||||||
|
if err, ok := err.(locationer); ok {
|
||||||
|
file, line := err.Location()
|
||||||
|
// Strip off the leading GOPATH/src path elements.
|
||||||
|
file = trimGoPath(file)
|
||||||
|
if file != "" {
|
||||||
|
buff = append(buff, fmt.Sprintf("%s:%d", file, line)...)
|
||||||
|
buff = append(buff, ": "...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cerr, ok := err.(wrapper); ok {
|
||||||
|
message := cerr.Message()
|
||||||
|
buff = append(buff, message...)
|
||||||
|
// If there is a cause for this error, and it is different to the cause
|
||||||
|
// of the underlying error, then output the error string in the stack trace.
|
||||||
|
var cause error
|
||||||
|
if err1, ok := err.(causer); ok {
|
||||||
|
cause = err1.Cause()
|
||||||
|
}
|
||||||
|
err = cerr.Underlying()
|
||||||
|
if cause != nil && !sameError(Cause(err), cause) {
|
||||||
|
if message != "" {
|
||||||
|
buff = append(buff, ": "...)
|
||||||
|
}
|
||||||
|
buff = append(buff, cause.Error()...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buff = append(buff, err.Error()...)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
lines = append(lines, string(buff))
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// reverse the lines to get the original error, which was at the end of
|
||||||
|
// the list, back to the start.
|
||||||
|
var result []string
|
||||||
|
for i := len(lines); i > 0; i-- {
|
||||||
|
result = append(result, lines[i-1])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
305
vendor/github.com/juju/errors/functions_test.go
generated
vendored
Normal file
305
vendor/github.com/juju/errors/functions_test.go
generated
vendored
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
// Copyright 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
jc "github.com/juju/testing/checkers"
|
||||||
|
gc "gopkg.in/check.v1"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type functionSuite struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = gc.Suite(&functionSuite{})
|
||||||
|
|
||||||
|
func (*functionSuite) TestNew(c *gc.C) {
|
||||||
|
err := errors.New("testing") //err newTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "testing")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["newTest"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestErrorf(c *gc.C) {
|
||||||
|
err := errors.Errorf("testing %d", 42) //err errorfTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "testing 42")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["errorfTest"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestTrace(c *gc.C) {
|
||||||
|
first := errors.New("first")
|
||||||
|
err := errors.Trace(first) //err traceTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "first")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["traceTest"].String())
|
||||||
|
|
||||||
|
c.Assert(errors.Trace(nil), gc.IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestAnnotate(c *gc.C) {
|
||||||
|
first := errors.New("first")
|
||||||
|
err := errors.Annotate(first, "annotation") //err annotateTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "annotation: first")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotateTest"].String())
|
||||||
|
|
||||||
|
c.Assert(errors.Annotate(nil, "annotate"), gc.IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestAnnotatef(c *gc.C) {
|
||||||
|
first := errors.New("first")
|
||||||
|
err := errors.Annotatef(first, "annotation %d", 2) //err annotatefTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "annotation 2: first")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotatefTest"].String())
|
||||||
|
|
||||||
|
c.Assert(errors.Annotatef(nil, "annotate"), gc.IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestDeferredAnnotatef(c *gc.C) {
|
||||||
|
// NOTE: this test fails with gccgo
|
||||||
|
if runtime.Compiler == "gccgo" {
|
||||||
|
c.Skip("gccgo can't determine the location")
|
||||||
|
}
|
||||||
|
first := errors.New("first")
|
||||||
|
test := func() (err error) {
|
||||||
|
defer errors.DeferredAnnotatef(&err, "deferred %s", "annotate")
|
||||||
|
return first //err deferredAnnotate
|
||||||
|
}
|
||||||
|
err := test()
|
||||||
|
c.Assert(err.Error(), gc.Equals, "deferred annotate: first")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["deferredAnnotate"].String())
|
||||||
|
|
||||||
|
err = nil
|
||||||
|
errors.DeferredAnnotatef(&err, "deferred %s", "annotate")
|
||||||
|
c.Assert(err, gc.IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestWrap(c *gc.C) {
|
||||||
|
first := errors.New("first") //err wrapFirst
|
||||||
|
detailed := errors.New("detailed")
|
||||||
|
err := errors.Wrap(first, detailed) //err wrapTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "detailed")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapFirst"].String())
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapTest"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestWrapOfNil(c *gc.C) {
|
||||||
|
detailed := errors.New("detailed")
|
||||||
|
err := errors.Wrap(nil, detailed) //err nilWrapTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "detailed")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapTest"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestWrapf(c *gc.C) {
|
||||||
|
first := errors.New("first") //err wrapfFirst
|
||||||
|
detailed := errors.New("detailed")
|
||||||
|
err := errors.Wrapf(first, detailed, "value %d", 42) //err wrapfTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "value 42: detailed")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfFirst"].String())
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfTest"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestWrapfOfNil(c *gc.C) {
|
||||||
|
detailed := errors.New("detailed")
|
||||||
|
err := errors.Wrapf(nil, detailed, "value %d", 42) //err nilWrapfTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "value 42: detailed")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapfTest"].String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestMask(c *gc.C) {
|
||||||
|
first := errors.New("first")
|
||||||
|
err := errors.Mask(first) //err maskTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "first")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskTest"].String())
|
||||||
|
|
||||||
|
c.Assert(errors.Mask(nil), gc.IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestMaskf(c *gc.C) {
|
||||||
|
first := errors.New("first")
|
||||||
|
err := errors.Maskf(first, "masked %d", 42) //err maskfTest
|
||||||
|
c.Assert(err.Error(), gc.Equals, "masked 42: first")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||||
|
c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskfTest"].String())
|
||||||
|
|
||||||
|
c.Assert(errors.Maskf(nil, "mask"), gc.IsNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestCause(c *gc.C) {
|
||||||
|
c.Assert(errors.Cause(nil), gc.IsNil)
|
||||||
|
c.Assert(errors.Cause(someErr), gc.Equals, someErr)
|
||||||
|
|
||||||
|
fmtErr := fmt.Errorf("simple")
|
||||||
|
c.Assert(errors.Cause(fmtErr), gc.Equals, fmtErr)
|
||||||
|
|
||||||
|
err := errors.Wrap(someErr, fmtErr)
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, fmtErr)
|
||||||
|
|
||||||
|
err = errors.Annotate(err, "annotated")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, fmtErr)
|
||||||
|
|
||||||
|
err = errors.Maskf(err, "maksed")
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||||
|
|
||||||
|
// Look for a file that we know isn't there.
|
||||||
|
dir := c.MkDir()
|
||||||
|
_, err = os.Stat(filepath.Join(dir, "not-there"))
|
||||||
|
c.Assert(os.IsNotExist(err), jc.IsTrue)
|
||||||
|
|
||||||
|
err = errors.Annotatef(err, "wrap it")
|
||||||
|
// Now the error itself isn't a 'IsNotExist'.
|
||||||
|
c.Assert(os.IsNotExist(err), jc.IsFalse)
|
||||||
|
// However if we use the Check method, it is.
|
||||||
|
c.Assert(os.IsNotExist(errors.Cause(err)), jc.IsTrue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *functionSuite) TestDetails(c *gc.C) {
|
||||||
|
if runtime.Compiler == "gccgo" {
|
||||||
|
c.Skip("gccgo can't determine the location")
|
||||||
|
}
|
||||||
|
c.Assert(errors.Details(nil), gc.Equals, "[]")
|
||||||
|
|
||||||
|
otherErr := fmt.Errorf("other")
|
||||||
|
checkDetails(c, otherErr, "[{other}]")
|
||||||
|
|
||||||
|
err0 := newEmbed("foo") //err TestStack#0
|
||||||
|
checkDetails(c, err0, "[{$TestStack#0$: foo}]")
|
||||||
|
|
||||||
|
err1 := errors.Annotate(err0, "bar") //err TestStack#1
|
||||||
|
checkDetails(c, err1, "[{$TestStack#1$: bar} {$TestStack#0$: foo}]")
|
||||||
|
|
||||||
|
err2 := errors.Trace(err1) //err TestStack#2
|
||||||
|
checkDetails(c, err2, "[{$TestStack#2$: } {$TestStack#1$: bar} {$TestStack#0$: foo}]")
|
||||||
|
}
|
||||||
|
|
||||||
|
type tracer interface {
|
||||||
|
StackTrace() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*functionSuite) TestErrorStack(c *gc.C) {
|
||||||
|
for i, test := range []struct {
|
||||||
|
message string
|
||||||
|
generator func() error
|
||||||
|
expected string
|
||||||
|
tracer bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
message: "nil",
|
||||||
|
generator: func() error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
message: "raw error",
|
||||||
|
generator: func() error {
|
||||||
|
return fmt.Errorf("raw")
|
||||||
|
},
|
||||||
|
expected: "raw",
|
||||||
|
}, {
|
||||||
|
message: "single error stack",
|
||||||
|
generator: func() error {
|
||||||
|
return errors.New("first error") //err single
|
||||||
|
},
|
||||||
|
expected: "$single$: first error",
|
||||||
|
tracer: true,
|
||||||
|
}, {
|
||||||
|
message: "annotated error",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.New("first error") //err annotated-0
|
||||||
|
return errors.Annotate(err, "annotation") //err annotated-1
|
||||||
|
},
|
||||||
|
expected: "" +
|
||||||
|
"$annotated-0$: first error\n" +
|
||||||
|
"$annotated-1$: annotation",
|
||||||
|
tracer: true,
|
||||||
|
}, {
|
||||||
|
message: "wrapped error",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.New("first error") //err wrapped-0
|
||||||
|
return errors.Wrap(err, newError("detailed error")) //err wrapped-1
|
||||||
|
},
|
||||||
|
expected: "" +
|
||||||
|
"$wrapped-0$: first error\n" +
|
||||||
|
"$wrapped-1$: detailed error",
|
||||||
|
tracer: true,
|
||||||
|
}, {
|
||||||
|
message: "annotated wrapped error",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.Errorf("first error") //err ann-wrap-0
|
||||||
|
err = errors.Wrap(err, fmt.Errorf("detailed error")) //err ann-wrap-1
|
||||||
|
return errors.Annotatef(err, "annotated") //err ann-wrap-2
|
||||||
|
},
|
||||||
|
expected: "" +
|
||||||
|
"$ann-wrap-0$: first error\n" +
|
||||||
|
"$ann-wrap-1$: detailed error\n" +
|
||||||
|
"$ann-wrap-2$: annotated",
|
||||||
|
tracer: true,
|
||||||
|
}, {
|
||||||
|
message: "traced, and annotated",
|
||||||
|
generator: func() error {
|
||||||
|
err := errors.New("first error") //err stack-0
|
||||||
|
err = errors.Trace(err) //err stack-1
|
||||||
|
err = errors.Annotate(err, "some context") //err stack-2
|
||||||
|
err = errors.Trace(err) //err stack-3
|
||||||
|
err = errors.Annotate(err, "more context") //err stack-4
|
||||||
|
return errors.Trace(err) //err stack-5
|
||||||
|
},
|
||||||
|
expected: "" +
|
||||||
|
"$stack-0$: first error\n" +
|
||||||
|
"$stack-1$: \n" +
|
||||||
|
"$stack-2$: some context\n" +
|
||||||
|
"$stack-3$: \n" +
|
||||||
|
"$stack-4$: more context\n" +
|
||||||
|
"$stack-5$: ",
|
||||||
|
tracer: true,
|
||||||
|
}, {
|
||||||
|
message: "uncomparable, wrapped with a value error",
|
||||||
|
generator: func() error {
|
||||||
|
err := newNonComparableError("first error") //err mixed-0
|
||||||
|
err = errors.Trace(err) //err mixed-1
|
||||||
|
err = errors.Wrap(err, newError("value error")) //err mixed-2
|
||||||
|
err = errors.Maskf(err, "masked") //err mixed-3
|
||||||
|
err = errors.Annotate(err, "more context") //err mixed-4
|
||||||
|
return errors.Trace(err) //err mixed-5
|
||||||
|
},
|
||||||
|
expected: "" +
|
||||||
|
"first error\n" +
|
||||||
|
"$mixed-1$: \n" +
|
||||||
|
"$mixed-2$: value error\n" +
|
||||||
|
"$mixed-3$: masked\n" +
|
||||||
|
"$mixed-4$: more context\n" +
|
||||||
|
"$mixed-5$: ",
|
||||||
|
tracer: true,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
c.Logf("%v: %s", i, test.message)
|
||||||
|
err := test.generator()
|
||||||
|
expected := replaceLocations(test.expected)
|
||||||
|
stack := errors.ErrorStack(err)
|
||||||
|
ok := c.Check(stack, gc.Equals, expected)
|
||||||
|
if !ok {
|
||||||
|
c.Logf("%#v", err)
|
||||||
|
}
|
||||||
|
tracer, ok := err.(tracer)
|
||||||
|
c.Check(ok, gc.Equals, test.tracer)
|
||||||
|
if ok {
|
||||||
|
stackTrace := tracer.StackTrace()
|
||||||
|
c.Check(stackTrace, gc.DeepEquals, strings.Split(stack, "\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
95
vendor/github.com/juju/errors/package_test.go
generated
vendored
Normal file
95
vendor/github.com/juju/errors/package_test.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// Copyright 2013, 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
gc "gopkg.in/check.v1"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test(t *testing.T) {
|
||||||
|
gc.TestingT(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkDetails(c *gc.C, err error, details string) {
|
||||||
|
c.Assert(err, gc.NotNil)
|
||||||
|
expectedDetails := replaceLocations(details)
|
||||||
|
c.Assert(errors.Details(err), gc.Equals, expectedDetails)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkErr(c *gc.C, err, cause error, msg string, details string) {
|
||||||
|
c.Assert(err, gc.NotNil)
|
||||||
|
c.Assert(err.Error(), gc.Equals, msg)
|
||||||
|
c.Assert(errors.Cause(err), gc.Equals, cause)
|
||||||
|
expectedDetails := replaceLocations(details)
|
||||||
|
c.Assert(errors.Details(err), gc.Equals, expectedDetails)
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceLocations(line string) string {
|
||||||
|
result := ""
|
||||||
|
for {
|
||||||
|
i := strings.Index(line, "$")
|
||||||
|
if i == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result += line[0:i]
|
||||||
|
line = line[i+1:]
|
||||||
|
i = strings.Index(line, "$")
|
||||||
|
if i == -1 {
|
||||||
|
panic("no second $")
|
||||||
|
}
|
||||||
|
result += location(line[0:i]).String()
|
||||||
|
line = line[i+1:]
|
||||||
|
}
|
||||||
|
result += line
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func location(tag string) Location {
|
||||||
|
loc, ok := tagToLocation[tag]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("tag %q not found", tag))
|
||||||
|
}
|
||||||
|
return loc
|
||||||
|
}
|
||||||
|
|
||||||
|
type Location struct {
|
||||||
|
file string
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (loc Location) String() string {
|
||||||
|
return fmt.Sprintf("%s:%d", loc.file, loc.line)
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagToLocation = make(map[string]Location)
|
||||||
|
|
||||||
|
func setLocationsForErrorTags(filename string) {
|
||||||
|
data, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
filename = "github.com/juju/errors/" + filename
|
||||||
|
lines := strings.Split(string(data), "\n")
|
||||||
|
for i, line := range lines {
|
||||||
|
if j := strings.Index(line, "//err "); j >= 0 {
|
||||||
|
tag := line[j+len("//err "):]
|
||||||
|
if _, found := tagToLocation[tag]; found {
|
||||||
|
panic(fmt.Sprintf("tag %q already processed previously", tag))
|
||||||
|
}
|
||||||
|
tagToLocation[tag] = Location{file: filename, line: i + 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
setLocationsForErrorTags("error_test.go")
|
||||||
|
setLocationsForErrorTags("functions_test.go")
|
||||||
|
}
|
38
vendor/github.com/juju/errors/path.go
generated
vendored
Normal file
38
vendor/github.com/juju/errors/path.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2013, 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// prefixSize is used internally to trim the user specific path from the
|
||||||
|
// front of the returned filenames from the runtime call stack.
|
||||||
|
var prefixSize int
|
||||||
|
|
||||||
|
// goPath is the deduced path based on the location of this file as compiled.
|
||||||
|
var goPath string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
_, file, _, ok := runtime.Caller(0)
|
||||||
|
if file == "?" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
// We know that the end of the file should be:
|
||||||
|
// github.com/juju/errors/path.go
|
||||||
|
size := len(file)
|
||||||
|
suffix := len("github.com/juju/errors/path.go")
|
||||||
|
goPath = file[:size-suffix]
|
||||||
|
prefixSize = len(goPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func trimGoPath(filename string) string {
|
||||||
|
if strings.HasPrefix(filename, goPath) {
|
||||||
|
return filename[prefixSize:]
|
||||||
|
}
|
||||||
|
return filename
|
||||||
|
}
|
29
vendor/github.com/juju/errors/path_test.go
generated
vendored
Normal file
29
vendor/github.com/juju/errors/path_test.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2013, 2014 Canonical Ltd.
|
||||||
|
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||||
|
|
||||||
|
package errors_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
|
||||||
|
gc "gopkg.in/check.v1"
|
||||||
|
|
||||||
|
"github.com/juju/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pathSuite struct{}
|
||||||
|
|
||||||
|
var _ = gc.Suite(&pathSuite{})
|
||||||
|
|
||||||
|
func (*pathSuite) TestGoPathSet(c *gc.C) {
|
||||||
|
c.Assert(errors.GoPath(), gc.Not(gc.Equals), "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*pathSuite) TestTrimGoPath(c *gc.C) {
|
||||||
|
relativeImport := "github.com/foo/bar/baz.go"
|
||||||
|
filename := path.Join(errors.GoPath(), relativeImport)
|
||||||
|
c.Assert(errors.TrimGoPath(filename), gc.Equals, relativeImport)
|
||||||
|
|
||||||
|
absoluteImport := "/usr/share/foo/bar/baz.go"
|
||||||
|
c.Assert(errors.TrimGoPath(absoluteImport), gc.Equals, absoluteImport)
|
||||||
|
}
|
Loading…
Reference in a new issue