mirror of
https://github.com/Luzifer/promcertcheck.git
synced 2024-11-08 07:50:05 +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
|
||||
promcertcheck
|
||||
|
|
12
Gopkg.lock
generated
12
Gopkg.lock
generated
|
@ -14,10 +14,10 @@
|
|||
revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/flosch/pongo2"
|
||||
packages = ["."]
|
||||
revision = "5e81b817a0c48c1c57cdf1a9056cf76bdee02ca9"
|
||||
version = "v3.0"
|
||||
revision = "1f4be1efe3b3529b7e58861f75d70120a9567dc4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -37,6 +37,12 @@
|
|||
revision = "24fca303ac6da784b9e8269f724ddeb0b2eea5e7"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/juju/errors"
|
||||
packages = ["."]
|
||||
revision = "c7d06af17c68cd34c835053720b21f6549d9b0ee"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
|
@ -112,6 +118,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "d0a90698569f49d4e7ef58586b857a1c7c60e48eaca07f1585d02e7ce91ca092"
|
||||
inputs-digest = "f88f786b9ff5e99b5589aea171923fd8d9dcef123a4d6be68d7659b923e8dc1e"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
[[constraint]]
|
||||
name = "github.com/flosch/pongo2"
|
||||
branch = "master"
|
||||
|
||||
[[constraint]]
|
||||
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
|
||||
_test
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[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
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- 1.7
|
||||
- tip
|
||||
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 gopkg.in/check.v1
|
||||
- go get github.com/juju/errors
|
||||
script:
|
||||
- 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'
|
||||
|
|
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
|
||||
|
||||
[![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)
|
||||
[![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/)
|
||||
[![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.
|
||||
|
||||
* 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`).
|
||||
* `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).
|
||||
|
@ -104,7 +106,7 @@ If you're using the `master`-branch of pongo2, you might be interested in this s
|
|||
## 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/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 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
|
||||
|
||||
* [pongo2 v3 released](https://www.florian-schlachter.de/post/pongo2-v3/)
|
||||
* [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 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.
|
||||
* [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
|
||||
* [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.
|
||||
|
||||
|
|
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
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.
|
||||
// Currently, context["pongo2"] contains the following keys:
|
||||
|
@ -25,13 +26,14 @@ func (c Context) checkForValidIdentifiers() *Error {
|
|||
if !reIdentifiers.MatchString(k) {
|
||||
return &Error{
|
||||
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
|
||||
}
|
||||
|
||||
// Update updates this context with the key/value-pairs from another context.
|
||||
func (c Context) Update(other Context) Context {
|
||||
for k, v := range other {
|
||||
c[k] = v
|
||||
|
@ -39,6 +41,8 @@ func (c Context) Update(other Context) Context {
|
|||
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
|
||||
// have access to the ExecutionContext. This struct stores anything
|
||||
// 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 {
|
||||
return ctx.OrigError(errors.New(msg), token)
|
||||
}
|
||||
|
||||
func (ctx *ExecutionContext) OrigError(err error, token *Token) *Error {
|
||||
filename := ctx.template.name
|
||||
var line, col int
|
||||
if token != nil {
|
||||
|
@ -113,7 +121,7 @@ func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
|
|||
Column: col,
|
||||
Token: token,
|
||||
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"
|
||||
)
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
@ -19,7 +19,7 @@ type Error struct {
|
|||
Column int
|
||||
Token *Token
|
||||
Sender string
|
||||
ErrorMsg string
|
||||
OrigError error
|
||||
}
|
||||
|
||||
func (e *Error) updateFromTokenIfNeeded(template *Template, t *Token) *Error {
|
||||
|
@ -54,14 +54,14 @@ func (e *Error) Error() string {
|
|||
}
|
||||
}
|
||||
s += "] "
|
||||
s += e.ErrorMsg
|
||||
s += e.OrigError.Error()
|
||||
return s
|
||||
}
|
||||
|
||||
// Returns the affected line from the original template, if available.
|
||||
func (e *Error) RawLine() (line string, available bool) {
|
||||
// RawLine returns the affected line from the original template, if available.
|
||||
func (e *Error) RawLine() (line string, available bool, outErr error) {
|
||||
if e.Line <= 0 || e.Filename == "<string>" {
|
||||
return "", false
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
filename := e.Filename
|
||||
|
@ -70,17 +70,22 @@ func (e *Error) RawLine() (line string, available bool) {
|
|||
}
|
||||
file, err := os.Open(filename)
|
||||
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)
|
||||
l := 0
|
||||
for scanner.Scan() {
|
||||
l++
|
||||
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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// FilterFunction is the type filter functions must fulfil
|
||||
type FilterFunction func(in *Value, param *Value) (out *Value, err *Error)
|
||||
|
||||
var filters map[string]FilterFunction
|
||||
|
@ -12,32 +15,38 @@ func init() {
|
|||
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
|
||||
// function in the filter's init() function:
|
||||
// http://golang.org/doc/effective_go.html#init
|
||||
//
|
||||
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
||||
// writing filters and tags.
|
||||
func RegisterFilter(name string, fn FilterFunction) {
|
||||
_, existing := filters[name]
|
||||
if existing {
|
||||
panic(fmt.Sprintf("Filter with name '%s' is already registered.", name))
|
||||
func RegisterFilter(name string, fn FilterFunction) error {
|
||||
if FilterExists(name) {
|
||||
return errors.Errorf("filter with name '%s' is already registered", name)
|
||||
}
|
||||
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.
|
||||
func ReplaceFilter(name string, fn FilterFunction) {
|
||||
_, existing := filters[name]
|
||||
if !existing {
|
||||
panic(fmt.Sprintf("Filter with name '%s' does not exist (therefore cannot be overridden).", name))
|
||||
func ReplaceFilter(name string, fn FilterFunction) error {
|
||||
if !FilterExists(name) {
|
||||
return errors.Errorf("filter with name '%s' does not exist (therefore cannot be overridden)", name)
|
||||
}
|
||||
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 {
|
||||
val, err := ApplyFilter(name, value, param)
|
||||
if err != nil {
|
||||
|
@ -46,13 +55,14 @@ func MustApplyFilter(name string, value *Value, param *Value) *Value {
|
|||
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) {
|
||||
fn, existing := filters[name]
|
||||
if !existing {
|
||||
return nil, &Error{
|
||||
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)
|
||||
}
|
||||
|
||||
filtered_value, err := fc.filterFunc(v, param)
|
||||
filteredValue, err := fc.filterFunc(v, param)
|
||||
if err != nil {
|
||||
return nil, err.updateFromTokenIfNeeded(ctx.template, fc.token)
|
||||
}
|
||||
return filtered_value, nil
|
||||
return filteredValue, nil
|
||||
}
|
||||
|
||||
// Filter = IDENT | IDENT ":" FilterArg | IDENT "|" Filter
|
||||
func (p *Parser) parseFilter() (*filterCall, *Error) {
|
||||
ident_token := p.MatchType(TokenIdentifier)
|
||||
identToken := p.MatchType(TokenIdentifier)
|
||||
|
||||
// Check filter ident
|
||||
if ident_token == nil {
|
||||
if identToken == nil {
|
||||
return nil, p.Error("Filter name must be an identifier.", nil)
|
||||
}
|
||||
|
||||
filter := &filterCall{
|
||||
token: ident_token,
|
||||
name: ident_token.Val,
|
||||
token: identToken,
|
||||
name: identToken.Val,
|
||||
}
|
||||
|
||||
// Get the appropriate filter function and bind it
|
||||
filterFn, exists := filters[ident_token.Val]
|
||||
filterFn, exists := filters[identToken.Val]
|
||||
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
|
||||
|
|
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"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -73,14 +75,15 @@ func init() {
|
|||
RegisterFilter("removetags", filterRemovetags)
|
||||
RegisterFilter("rjust", filterRjust)
|
||||
RegisterFilter("slice", filterSlice)
|
||||
RegisterFilter("split", filterSplit)
|
||||
RegisterFilter("stringformat", filterStringformat)
|
||||
RegisterFilter("striptags", filterStriptags)
|
||||
RegisterFilter("time", filterDate) // time uses filterDate (same golang-format)
|
||||
RegisterFilter("title", filterTitle)
|
||||
RegisterFilter("truncatechars", filterTruncatechars)
|
||||
RegisterFilter("truncatechars_html", filterTruncatecharsHtml)
|
||||
RegisterFilter("truncatechars_html", filterTruncatecharsHTML)
|
||||
RegisterFilter("truncatewords", filterTruncatewords)
|
||||
RegisterFilter("truncatewords_html", filterTruncatewordsHtml)
|
||||
RegisterFilter("truncatewords_html", filterTruncatewordsHTML)
|
||||
RegisterFilter("upper", filterUpper)
|
||||
RegisterFilter("urlencode", filterUrlencode)
|
||||
RegisterFilter("urlize", filterUrlize)
|
||||
|
@ -105,9 +108,9 @@ func filterTruncatecharsHelper(s string, newLen int) string {
|
|||
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)
|
||||
tag_stack := make([]string, 0)
|
||||
var tagStack []string
|
||||
idx := 0
|
||||
|
||||
for idx < vLen && !cond() {
|
||||
|
@ -118,17 +121,17 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
}
|
||||
|
||||
if c == '<' {
|
||||
new_output.WriteRune(c)
|
||||
newOutput.WriteRune(c)
|
||||
idx += s // consume "<"
|
||||
|
||||
if idx+1 < vLen {
|
||||
if value[idx] == '/' {
|
||||
// Close tag
|
||||
|
||||
new_output.WriteString("/")
|
||||
newOutput.WriteString("/")
|
||||
|
||||
tag := ""
|
||||
idx += 1 // consume "/"
|
||||
idx++ // consume "/"
|
||||
|
||||
for idx < vLen {
|
||||
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
||||
|
@ -146,21 +149,21 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
idx += size2
|
||||
}
|
||||
|
||||
if len(tag_stack) > 0 {
|
||||
if len(tagStack) > 0 {
|
||||
// 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
|
||||
for i := len(tag_stack) - 1; i >= 0; i-- {
|
||||
if tag_stack[i] == tag {
|
||||
for i := len(tagStack) - 1; i >= 0; i-- {
|
||||
if tagStack[i] == tag {
|
||||
// Found the tag
|
||||
tag_stack[i] = tag_stack[len(tag_stack)-1]
|
||||
tag_stack = tag_stack[:len(tag_stack)-1]
|
||||
tagStack[i] = tagStack[len(tagStack)-1]
|
||||
tagStack = tagStack[:len(tagStack)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_output.WriteString(tag)
|
||||
new_output.WriteString(">")
|
||||
newOutput.WriteString(tag)
|
||||
newOutput.WriteString(">")
|
||||
} else {
|
||||
// Open tag
|
||||
|
||||
|
@ -174,7 +177,7 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
continue
|
||||
}
|
||||
|
||||
new_output.WriteRune(c2)
|
||||
newOutput.WriteRune(c2)
|
||||
|
||||
// End of tag found
|
||||
if c2 == '>' {
|
||||
|
@ -194,7 +197,7 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
}
|
||||
|
||||
// Add tag to stack
|
||||
tag_stack = append(tag_stack, tag)
|
||||
tagStack = append(tagStack, tag)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -204,10 +207,10 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
|
||||
finalize()
|
||||
|
||||
for i := len(tag_stack) - 1; i >= 0; i-- {
|
||||
tag := tag_stack[i]
|
||||
for i := len(tagStack) - 1; i >= 0; i-- {
|
||||
tag := tagStack[i]
|
||||
// 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
|
||||
}
|
||||
|
||||
func filterTruncatecharsHtml(in *Value, param *Value) (*Value, *Error) {
|
||||
func filterTruncatecharsHTML(in *Value, param *Value) (*Value, *Error) {
|
||||
value := in.String()
|
||||
newLen := max(param.Integer()-3, 0)
|
||||
|
||||
new_output := bytes.NewBuffer(nil)
|
||||
newOutput := bytes.NewBuffer(nil)
|
||||
|
||||
textcounter := 0
|
||||
|
||||
filterTruncateHtmlHelper(value, new_output, func() bool {
|
||||
filterTruncateHTMLHelper(value, newOutput, func() bool {
|
||||
return textcounter >= newLen
|
||||
}, func(c rune, s int, idx int) int {
|
||||
textcounter++
|
||||
new_output.WriteRune(c)
|
||||
newOutput.WriteRune(c)
|
||||
|
||||
return idx + s
|
||||
}, func() {
|
||||
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) {
|
||||
|
@ -260,19 +263,19 @@ func filterTruncatewords(in *Value, param *Value) (*Value, *Error) {
|
|||
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()
|
||||
newLen := max(param.Integer(), 0)
|
||||
|
||||
new_output := bytes.NewBuffer(nil)
|
||||
newOutput := bytes.NewBuffer(nil)
|
||||
|
||||
wordcounter := 0
|
||||
|
||||
filterTruncateHtmlHelper(value, new_output, func() bool {
|
||||
filterTruncateHTMLHelper(value, newOutput, func() bool {
|
||||
return wordcounter >= newLen
|
||||
}, func(_ rune, _ int, idx int) int {
|
||||
// Get next word
|
||||
word_found := false
|
||||
wordFound := false
|
||||
|
||||
for idx < len(value) {
|
||||
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
||||
|
@ -286,29 +289,29 @@ func filterTruncatewordsHtml(in *Value, param *Value) (*Value, *Error) {
|
|||
return idx
|
||||
}
|
||||
|
||||
new_output.WriteRune(c2)
|
||||
newOutput.WriteRune(c2)
|
||||
idx += size2
|
||||
|
||||
if c2 == ' ' || c2 == '.' || c2 == ',' || c2 == ';' {
|
||||
// Word ends here, stop capturing it now
|
||||
break
|
||||
} else {
|
||||
word_found = true
|
||||
wordFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if word_found {
|
||||
if wordFound {
|
||||
wordcounter++
|
||||
}
|
||||
|
||||
return idx
|
||||
}, func() {
|
||||
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) {
|
||||
|
@ -377,12 +380,11 @@ func filterAdd(in *Value, param *Value) (*Value, *Error) {
|
|||
if in.IsNumber() && param.IsNumber() {
|
||||
if in.IsFloat() || param.IsFloat() {
|
||||
return AsValue(in.Float() + param.Float()), nil
|
||||
} else {
|
||||
}
|
||||
return AsValue(in.Integer() + param.Integer()), nil
|
||||
}
|
||||
}
|
||||
// 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
|
||||
}
|
||||
|
||||
|
@ -550,11 +552,11 @@ func filterCenter(in *Value, param *Value) (*Value, *Error) {
|
|||
}
|
||||
|
||||
func filterDate(in *Value, param *Value) (*Value, *Error) {
|
||||
t, is_time := in.Interface().(time.Time)
|
||||
if !is_time {
|
||||
t, isTime := in.Interface().(time.Time)
|
||||
if !isTime {
|
||||
return nil, &Error{
|
||||
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
|
||||
|
@ -612,6 +614,12 @@ func filterLinebreaks(in *Value, param *Value) (*Value, *Error) {
|
|||
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) {
|
||||
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 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 {
|
||||
var prefix 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)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
soutErr = err
|
||||
return ""
|
||||
}
|
||||
url := t.String()
|
||||
|
||||
|
@ -673,16 +683,19 @@ func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
|||
if autoescape {
|
||||
t, err := ApplyFilter("escape", AsValue(title), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
soutErr = err
|
||||
return ""
|
||||
}
|
||||
title = t.String()
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
title := mail
|
||||
|
||||
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 sout
|
||||
return sout, nil
|
||||
}
|
||||
|
||||
func filterUrlize(in *Value, param *Value) (*Value, *Error) {
|
||||
|
@ -701,24 +714,36 @@ func filterUrlize(in *Value, param *Value) (*Value, *Error) {
|
|||
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) {
|
||||
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) {
|
||||
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) {
|
||||
s := in.String()
|
||||
|
||||
// Strip all tags
|
||||
s = re_striptags.ReplaceAllString(s, "")
|
||||
s = reStriptags.ReplaceAllString(s, "")
|
||||
|
||||
return AsValue(strings.TrimSpace(s)), nil
|
||||
}
|
||||
|
@ -747,7 +772,7 @@ func filterPluralize(in *Value, param *Value) (*Value, *Error) {
|
|||
if len(endings) > 2 {
|
||||
return nil, &Error{
|
||||
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 {
|
||||
|
@ -770,11 +795,10 @@ func filterPluralize(in *Value, param *Value) (*Value, *Error) {
|
|||
}
|
||||
|
||||
return AsValue(""), nil
|
||||
} else {
|
||||
}
|
||||
return nil, &Error{
|
||||
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 {
|
||||
return nil, &Error{
|
||||
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) {
|
||||
words := strings.Fields(in.String())
|
||||
words_len := len(words)
|
||||
wrap_at := param.Integer()
|
||||
if wrap_at <= 0 {
|
||||
wordsLen := len(words)
|
||||
wrapAt := param.Integer()
|
||||
if wrapAt <= 0 {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
linecount := words_len/wrap_at + words_len%wrap_at
|
||||
linecount := wordsLen/wrapAt + wordsLen%wrapAt
|
||||
lines := make([]string, 0, linecount)
|
||||
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
|
||||
}
|
||||
|
@ -864,27 +888,27 @@ func filterYesno(in *Value, param *Value) (*Value, *Error) {
|
|||
1: "no",
|
||||
2: "maybe",
|
||||
}
|
||||
param_string := param.String()
|
||||
custom_choices := strings.Split(param_string, ",")
|
||||
if len(param_string) > 0 {
|
||||
if len(custom_choices) > 3 {
|
||||
paramString := param.String()
|
||||
customChoices := strings.Split(paramString, ",")
|
||||
if len(paramString) > 0 {
|
||||
if len(customChoices) > 3 {
|
||||
return nil, &Error{
|
||||
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{
|
||||
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
|
||||
choices[0] = custom_choices[0]
|
||||
choices[1] = custom_choices[1]
|
||||
if len(custom_choices) == 3 {
|
||||
choices[2] = custom_choices[2]
|
||||
choices[0] = customChoices[0]
|
||||
choices[1] = customChoices[1]
|
||||
if len(customChoices) == 3 {
|
||||
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"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -63,8 +65,8 @@ type lexer struct {
|
|||
line int
|
||||
col int
|
||||
|
||||
in_verbatim bool
|
||||
verbatim_name string
|
||||
inVerbatim bool
|
||||
verbatimName string
|
||||
}
|
||||
|
||||
func (t *Token) String() string {
|
||||
|
@ -115,7 +117,7 @@ func lex(name string, input string) ([]*Token, *Error) {
|
|||
Line: errtoken.Line,
|
||||
Column: errtoken.Col,
|
||||
Sender: "lexer",
|
||||
ErrorMsg: errtoken.Val,
|
||||
OrigError: errors.New(errtoken.Val),
|
||||
}
|
||||
}
|
||||
return l.tokens, nil
|
||||
|
@ -216,8 +218,8 @@ func (l *lexer) run() {
|
|||
for {
|
||||
// TODO: Support verbatim tag names
|
||||
// https://docs.djangoproject.com/en/dev/ref/templates/builtins/#verbatim
|
||||
if l.in_verbatim {
|
||||
name := l.verbatim_name
|
||||
if l.inVerbatim {
|
||||
name := l.verbatimName
|
||||
if name != "" {
|
||||
name += " "
|
||||
}
|
||||
|
@ -229,20 +231,20 @@ func (l *lexer) run() {
|
|||
l.pos += w
|
||||
l.col += w
|
||||
l.ignore()
|
||||
l.in_verbatim = false
|
||||
l.inVerbatim = false
|
||||
}
|
||||
} else if strings.HasPrefix(l.input[l.pos:], "{% verbatim %}") { // tag
|
||||
if l.pos > l.start {
|
||||
l.emit(TokenHTML)
|
||||
}
|
||||
l.in_verbatim = true
|
||||
l.inVerbatim = true
|
||||
w := len("{% verbatim %}")
|
||||
l.pos += w
|
||||
l.col += w
|
||||
l.ignore()
|
||||
}
|
||||
|
||||
if !l.in_verbatim {
|
||||
if !l.inVerbatim {
|
||||
// Ignore single-line comments {# ... #}
|
||||
if strings.HasPrefix(l.input[l.pos:], "{#") {
|
||||
if l.pos > l.start {
|
||||
|
@ -303,7 +305,7 @@ func (l *lexer) run() {
|
|||
l.emit(TokenHTML)
|
||||
}
|
||||
|
||||
if l.in_verbatim {
|
||||
if l.inVerbatim {
|
||||
l.errorf("verbatim-tag not closed, got EOF.")
|
||||
}
|
||||
}
|
||||
|
@ -328,7 +330,7 @@ outer_loop:
|
|||
return l.stateIdentifier
|
||||
case l.accept(tokenDigits):
|
||||
return l.stateNumber
|
||||
case l.accept(`"`):
|
||||
case l.accept(`"'`):
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -374,6 +372,11 @@ func (l *lexer) stateIdentifier() lexerStateFn {
|
|||
|
||||
func (l *lexer) stateNumber() lexerStateFn {
|
||||
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?
|
||||
* comments.0.Text // first comment
|
||||
|
@ -393,9 +396,10 @@ func (l *lexer) stateNumber() lexerStateFn {
|
|||
}
|
||||
|
||||
func (l *lexer) stateString() lexerStateFn {
|
||||
quotationMark := l.value()
|
||||
l.ignore()
|
||||
l.startcol -= 1 // we're starting the position at the first "
|
||||
for !l.accept(`"`) {
|
||||
l.startcol-- // we're starting the position at the first "
|
||||
for !l.accept(quotationMark) {
|
||||
switch l.next() {
|
||||
case '\\':
|
||||
// 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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// The root document
|
||||
type nodeDocument struct {
|
||||
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 {
|
||||
err := n.Execute(ctx, buffer)
|
||||
err := n.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type nodeHTML struct {
|
||||
token *Token
|
||||
}
|
||||
|
||||
func (n *nodeHTML) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
buffer.WriteString(n.token.Val)
|
||||
func (n *nodeHTML) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
writer.WriteString(n.token.Val)
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type NodeWrapper struct {
|
||||
Endtag string
|
||||
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 {
|
||||
err := n.Execute(ctx, buffer)
|
||||
err := n.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type INode interface {
|
||||
Execute(*ExecutionContext, *bytes.Buffer) *Error
|
||||
Execute(*ExecutionContext, TemplateWriter) *Error
|
||||
}
|
||||
|
||||
type IEvaluator interface {
|
||||
|
@ -30,7 +31,7 @@ type Parser struct {
|
|||
name string
|
||||
idx int
|
||||
tokens []*Token
|
||||
last_token *Token
|
||||
lastToken *Token
|
||||
|
||||
// if the parser parses a template document, here will be
|
||||
// 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,
|
||||
}
|
||||
if len(tokens) > 0 {
|
||||
p.last_token = tokens[len(tokens)-1]
|
||||
p.lastToken = tokens[len(tokens)-1]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
@ -175,7 +176,7 @@ func (p *Parser) GetR(shift int) *Token {
|
|||
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's position information. If not provided, it will
|
||||
// automatically use the CURRENT token's position information.
|
||||
|
@ -202,7 +203,7 @@ func (p *Parser) Error(msg string, token *Token) *Error {
|
|||
Line: line,
|
||||
Column: col,
|
||||
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) {
|
||||
wrapper := &NodeWrapper{}
|
||||
|
||||
tagArgs := make([]*Token, 0)
|
||||
var tagArgs []*Token
|
||||
|
||||
for p.Remaining() > 0 {
|
||||
// New tag, check whether we have to stop wrapping here
|
||||
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
|
||||
|
||||
found := false
|
||||
for _, n := range names {
|
||||
if tag_ident.Val == n {
|
||||
if tagIdent.Val == n {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
@ -238,19 +239,18 @@ func (p *Parser) WrapUntilTag(names ...string) (*NodeWrapper, *Parser, *Error) {
|
|||
for {
|
||||
if p.Match(TokenSymbol, "%}") != nil {
|
||||
// Okay, end the wrapping here
|
||||
wrapper.Endtag = tag_ident.Val
|
||||
wrapper.Endtag = tagIdent.Val
|
||||
return wrapper, newParser(p.template.name, tagArgs, p.template), nil
|
||||
} else {
|
||||
}
|
||||
t := p.Current()
|
||||
p.Consume()
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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 ")),
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
@ -10,29 +9,29 @@ type Expression struct {
|
|||
// TODO: Add location token?
|
||||
expr1 IEvaluator
|
||||
expr2 IEvaluator
|
||||
op_token *Token
|
||||
opToken *Token
|
||||
}
|
||||
|
||||
type relationalExpression struct {
|
||||
// TODO: Add location token?
|
||||
expr1 IEvaluator
|
||||
expr2 IEvaluator
|
||||
op_token *Token
|
||||
opToken *Token
|
||||
}
|
||||
|
||||
type simpleExpression struct {
|
||||
negate bool
|
||||
negative_sign bool
|
||||
negativeSign bool
|
||||
term1 IEvaluator
|
||||
term2 IEvaluator
|
||||
op_token *Token
|
||||
opToken *Token
|
||||
}
|
||||
|
||||
type term struct {
|
||||
// TODO: Add location token?
|
||||
factor1 IEvaluator
|
||||
factor2 IEvaluator
|
||||
op_token *Token
|
||||
opToken *Token
|
||||
}
|
||||
|
||||
type power struct {
|
||||
|
@ -56,14 +55,14 @@ func (expr *simpleExpression) FilterApplied(name string) bool {
|
|||
(expr.term2 != nil && expr.term2.FilterApplied(name)))
|
||||
}
|
||||
|
||||
func (t *term) FilterApplied(name string) bool {
|
||||
return t.factor1.FilterApplied(name) && (t.factor2 == nil ||
|
||||
(t.factor2 != nil && t.factor2.FilterApplied(name)))
|
||||
func (expr *term) FilterApplied(name string) bool {
|
||||
return expr.factor1.FilterApplied(name) && (expr.factor2 == nil ||
|
||||
(expr.factor2 != nil && expr.factor2.FilterApplied(name)))
|
||||
}
|
||||
|
||||
func (p *power) FilterApplied(name string) bool {
|
||||
return p.power1.FilterApplied(name) && (p.power2 == nil ||
|
||||
(p.power2 != nil && p.power2.FilterApplied(name)))
|
||||
func (expr *power) FilterApplied(name string) bool {
|
||||
return expr.power1.FilterApplied(name) && (expr.power2 == nil ||
|
||||
(expr.power2 != nil && expr.power2.FilterApplied(name)))
|
||||
}
|
||||
|
||||
func (expr *Expression) GetPositionToken() *Token {
|
||||
|
@ -86,48 +85,48 @@ func (expr *power) GetPositionToken() *Token {
|
|||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -141,13 +140,13 @@ func (expr *Expression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch expr.op_token.Val {
|
||||
switch expr.opToken.Val {
|
||||
case "and", "&&":
|
||||
return AsValue(v1.IsTrue() && v2.IsTrue()), nil
|
||||
case "or", "||":
|
||||
return AsValue(v1.IsTrue() || v2.IsTrue()), nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unimplemented: %s", expr.op_token.Val))
|
||||
return nil, ctx.Error(fmt.Sprintf("unimplemented: %s", expr.opToken.Val), expr.opToken)
|
||||
}
|
||||
} else {
|
||||
return v1, nil
|
||||
|
@ -164,39 +163,35 @@ func (expr *relationalExpression) Evaluate(ctx *ExecutionContext) (*Value, *Erro
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch expr.op_token.Val {
|
||||
switch expr.opToken.Val {
|
||||
case "<=":
|
||||
if v1.IsFloat() || v2.IsFloat() {
|
||||
return AsValue(v1.Float() <= v2.Float()), nil
|
||||
} else {
|
||||
return AsValue(v1.Integer() <= v2.Integer()), nil
|
||||
}
|
||||
return AsValue(v1.Integer() <= v2.Integer()), nil
|
||||
case ">=":
|
||||
if v1.IsFloat() || v2.IsFloat() {
|
||||
return AsValue(v1.Float() >= v2.Float()), nil
|
||||
} else {
|
||||
return AsValue(v1.Integer() >= v2.Integer()), nil
|
||||
}
|
||||
return AsValue(v1.Integer() >= v2.Integer()), nil
|
||||
case "==":
|
||||
return AsValue(v1.EqualValueTo(v2)), nil
|
||||
case ">":
|
||||
if v1.IsFloat() || v2.IsFloat() {
|
||||
return AsValue(v1.Float() > v2.Float()), nil
|
||||
} else {
|
||||
return AsValue(v1.Integer() > v2.Integer()), nil
|
||||
}
|
||||
return AsValue(v1.Integer() > v2.Integer()), nil
|
||||
case "<":
|
||||
if v1.IsFloat() || v2.IsFloat() {
|
||||
return AsValue(v1.Float() < v2.Float()), nil
|
||||
} else {
|
||||
return AsValue(v1.Integer() < v2.Integer()), nil
|
||||
}
|
||||
return AsValue(v1.Integer() < v2.Integer()), nil
|
||||
case "!=", "<>":
|
||||
return AsValue(!v1.EqualValueTo(v2)), nil
|
||||
case "in":
|
||||
return AsValue(v2.Contains(v1)), nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unimplemented: %s", expr.op_token.Val))
|
||||
return nil, ctx.Error(fmt.Sprintf("unimplemented: %s", expr.opToken.Val), expr.opToken)
|
||||
}
|
||||
} else {
|
||||
return v1, nil
|
||||
|
@ -214,7 +209,7 @@ func (expr *simpleExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
|||
result = result.Negate()
|
||||
}
|
||||
|
||||
if expr.negative_sign {
|
||||
if expr.negativeSign {
|
||||
if result.IsNumber() {
|
||||
switch {
|
||||
case result.IsFloat():
|
||||
|
@ -222,7 +217,7 @@ func (expr *simpleExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
|||
case result.IsInteger():
|
||||
result = AsValue(-1 * result.Integer())
|
||||
default:
|
||||
panic("not possible")
|
||||
return nil, ctx.Error("Operation between a number and a non-(float/integer) is not possible", nil)
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
switch expr.op_token.Val {
|
||||
switch expr.opToken.Val {
|
||||
case "+":
|
||||
if result.IsFloat() || t2.IsFloat() {
|
||||
// Result will be a float
|
||||
return AsValue(result.Float() + t2.Float()), nil
|
||||
} else {
|
||||
}
|
||||
// Result will be an integer
|
||||
return AsValue(result.Integer() + t2.Integer()), nil
|
||||
}
|
||||
case "-":
|
||||
if result.IsFloat() || t2.IsFloat() {
|
||||
// Result will be a float
|
||||
return AsValue(result.Float() - t2.Float()), nil
|
||||
} else {
|
||||
}
|
||||
// Result will be an integer
|
||||
return AsValue(result.Integer() - t2.Integer()), nil
|
||||
}
|
||||
default:
|
||||
panic("unimplemented")
|
||||
return nil, ctx.Error("Unimplemented", expr.GetPositionToken())
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (t *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||
f1, err := t.factor1.Evaluate(ctx)
|
||||
func (expr *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||
f1, err := expr.factor1.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if t.factor2 != nil {
|
||||
f2, err := t.factor2.Evaluate(ctx)
|
||||
if expr.factor2 != nil {
|
||||
f2, err := expr.factor2.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch t.op_token.Val {
|
||||
switch expr.opToken.Val {
|
||||
case "*":
|
||||
if f1.IsFloat() || f2.IsFloat() {
|
||||
// Result will be float
|
||||
|
@ -288,27 +281,26 @@ func (t *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
|||
// Result will be int
|
||||
return AsValue(f1.Integer() % f2.Integer()), nil
|
||||
default:
|
||||
panic("unimplemented")
|
||||
return nil, ctx.Error("unimplemented", expr.opToken)
|
||||
}
|
||||
} else {
|
||||
return f1, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (pw *power) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||
p1, err := pw.power1.Evaluate(ctx)
|
||||
func (expr *power) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||
p1, err := expr.power1.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pw.power2 != nil {
|
||||
p2, err := pw.power2.Evaluate(ctx)
|
||||
if expr.power2 != nil {
|
||||
p2, err := expr.power2.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return AsValue(math.Pow(p1.Float(), p2.Float())), nil
|
||||
} else {
|
||||
return p1, nil
|
||||
}
|
||||
return p1, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseFactor() (IEvaluator, *Error) {
|
||||
|
@ -352,19 +344,19 @@ func (p *Parser) parsePower() (IEvaluator, *Error) {
|
|||
}
|
||||
|
||||
func (p *Parser) parseTerm() (IEvaluator, *Error) {
|
||||
return_term := new(term)
|
||||
returnTerm := new(term)
|
||||
|
||||
factor1, err := p.parsePower()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return_term.factor1 = factor1
|
||||
returnTerm.factor1 = factor1
|
||||
|
||||
for p.PeekOne(TokenSymbol, "*", "/", "%") != nil {
|
||||
if return_term.op_token != nil {
|
||||
if returnTerm.opToken != nil {
|
||||
// Create new sub-term
|
||||
return_term = &term{
|
||||
factor1: return_term,
|
||||
returnTerm = &term{
|
||||
factor1: returnTerm,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,16 +368,16 @@ func (p *Parser) parseTerm() (IEvaluator, *Error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return_term.op_token = op
|
||||
return_term.factor2 = factor2
|
||||
returnTerm.opToken = op
|
||||
returnTerm.factor2 = factor2
|
||||
}
|
||||
|
||||
if return_term.op_token == nil {
|
||||
if returnTerm.opToken == nil {
|
||||
// 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) {
|
||||
|
@ -393,7 +385,7 @@ func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
|||
|
||||
if sign := p.MatchOne(TokenSymbol, "+", "-"); sign != nil {
|
||||
if sign.Val == "-" {
|
||||
expr.negative_sign = true
|
||||
expr.negativeSign = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,7 +400,7 @@ func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
|||
expr.term1 = term1
|
||||
|
||||
for p.PeekOne(TokenSymbol, "+", "-") != nil {
|
||||
if expr.op_token != nil {
|
||||
if expr.opToken != nil {
|
||||
// New sub expr
|
||||
expr = &simpleExpression{
|
||||
term1: expr,
|
||||
|
@ -424,10 +416,10 @@ func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
|
|||
}
|
||||
|
||||
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
|
||||
return expr.term1, nil
|
||||
}
|
||||
|
@ -450,14 +442,14 @@ func (p *Parser) parseRelationalExpression() (IEvaluator, *Error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expr.op_token = t
|
||||
expr.opToken = t
|
||||
expr.expr2 = expr2
|
||||
} else if t := p.MatchOne(TokenKeyword, "in"); t != nil {
|
||||
expr2, err := p.parseSimpleExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expr.op_token = t
|
||||
expr.opToken = t
|
||||
expr.expr2 = expr2
|
||||
}
|
||||
|
||||
|
@ -487,7 +479,7 @@ func (p *Parser) ParseExpression() (IEvaluator, *Error) {
|
|||
return nil, err
|
||||
}
|
||||
exp.expr2 = expr2
|
||||
exp.op_token = op
|
||||
exp.opToken = op
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// Version string
|
||||
const Version = "v3"
|
||||
const Version = "dev"
|
||||
|
||||
// Helper function which panics, if a Template couldn't
|
||||
// successfully parsed. This is how you would use it:
|
||||
// Must panics, if a Template couldn't successfully parsed. This is how you
|
||||
// would use it:
|
||||
// var baseTemplate = pongo2.Must(pongo2.FromFile("templates/base.html"))
|
||||
func Must(tpl *Template, err error) *Template {
|
||||
if err != nil {
|
||||
|
|
35
vendor/github.com/flosch/pongo2/pongo2_issues_test.go
generated
vendored
35
vendor/github.com/flosch/pongo2/pongo2_issues_test.go
generated
vendored
|
@ -1,20 +1,29 @@
|
|||
package pongo2
|
||||
package pongo2_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
"github.com/flosch/pongo2"
|
||||
)
|
||||
|
||||
// Hook up gocheck into the "go test" runner.
|
||||
|
||||
func TestIssues(t *testing.T) { TestingT(t) }
|
||||
|
||||
type IssueTestSuite struct{}
|
||||
|
||||
var _ = Suite(&IssueTestSuite{})
|
||||
|
||||
func (s *TestSuite) TestIssues(c *C) {
|
||||
// Add a test for any issue
|
||||
c.Check(42, Equals, 42)
|
||||
func TestIssue151(t *testing.T) {
|
||||
tpl, err := pongo2.FromString("{{ mydict.51232_3 }}{{ 12345_123}}{{ 995189baz }}")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
str, err := tpl.Execute(pongo2.Context{
|
||||
"mydict": map[string]string{
|
||||
"51232_3": "foo",
|
||||
},
|
||||
"12345_123": "bar",
|
||||
"995189baz": "baz",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if str != "foobarbaz" {
|
||||
t.Fatalf("Expected output 'foobarbaz', but got '%s'.", str)
|
||||
}
|
||||
}
|
||||
|
|
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 (
|
||||
"bytes"
|
||||
|
@ -9,9 +9,11 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"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 time2 = time.Date(2011, 03, 21, 8, 37, 56, 12, time.UTC)
|
||||
|
@ -32,8 +34,8 @@ type comment struct {
|
|||
Text string
|
||||
}
|
||||
|
||||
func is_admin(u *user) bool {
|
||||
for _, a := range admin_list {
|
||||
func isAdmin(u *user) bool {
|
||||
for _, a := range adminList {
|
||||
if a == u.Name {
|
||||
return true
|
||||
}
|
||||
|
@ -41,12 +43,12 @@ func is_admin(u *user) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (u *user) Is_admin() *Value {
|
||||
return AsValue(is_admin(u))
|
||||
func (u *user) Is_admin() *pongo2.Value {
|
||||
return pongo2.AsValue(isAdmin(u))
|
||||
}
|
||||
|
||||
func (u *user) Is_admin2() bool {
|
||||
return is_admin(u)
|
||||
return isAdmin(u)
|
||||
}
|
||||
|
||||
func (p *post) String() string {
|
||||
|
@ -60,70 +62,49 @@ func (p *post) String() string {
|
|||
type tagSandboxDemoTag struct {
|
||||
}
|
||||
|
||||
func (node *tagSandboxDemoTag) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
buffer.WriteString("hello")
|
||||
func (node *tagSandboxDemoTag) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) *pongo2.Error {
|
||||
writer.WriteString("hello")
|
||||
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
|
||||
}
|
||||
|
||||
func BannedFilterFn(in *Value, params *Value) (*Value, *Error) {
|
||||
func BannedFilterFn(in *pongo2.Value, params *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
|
||||
return in, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
DefaultSet.Debug = true
|
||||
pongo2.DefaultSet.Debug = true
|
||||
|
||||
RegisterFilter("banned_filter", BannedFilterFn)
|
||||
RegisterFilter("unbanned_filter", BannedFilterFn)
|
||||
RegisterTag("banned_tag", tagSandboxDemoTagParser)
|
||||
RegisterTag("unbanned_tag", tagSandboxDemoTagParser)
|
||||
pongo2.RegisterFilter("banned_filter", BannedFilterFn)
|
||||
pongo2.RegisterFilter("unbanned_filter", BannedFilterFn)
|
||||
pongo2.RegisterTag("banned_tag", tagSandboxDemoTagParser)
|
||||
pongo2.RegisterTag("unbanned_tag", tagSandboxDemoTagParser)
|
||||
|
||||
DefaultSet.BanFilter("banned_filter")
|
||||
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_*")
|
||||
pongo2.DefaultSet.BanFilter("banned_filter")
|
||||
pongo2.DefaultSet.BanTag("banned_tag")
|
||||
|
||||
f, err := ioutil.TempFile("/tmp/", "pongo2_")
|
||||
if err != nil {
|
||||
panic("cannot write to /tmp/")
|
||||
}
|
||||
f.Write([]byte("Hello from pongo2"))
|
||||
DefaultSet.Globals["temp_file"] = f.Name()
|
||||
pongo2.DefaultSet.Globals["temp_file"] = f.Name()
|
||||
}
|
||||
|
||||
/*
|
||||
* End setup sandbox
|
||||
*/
|
||||
|
||||
var tplContext = Context{
|
||||
var tplContext = pongo2.Context{
|
||||
"number": 11,
|
||||
"simple": map[string]interface{}{
|
||||
"number": 42,
|
||||
"name": "john doe",
|
||||
"included_file": "INCLUDES.helper",
|
||||
"included_file_not_exists": "INCLUDES.helper.not_exists",
|
||||
"nil": nil,
|
||||
"uint": uint(8),
|
||||
"float": float64(3.1415),
|
||||
|
@ -142,13 +123,23 @@ Yep!`,
|
|||
"escape_js_test": `escape sequences \r\n\'\" special chars "?!=$<>`,
|
||||
"one_item_list": []int{99},
|
||||
"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"},
|
||||
"escape_text": "This is \\a Test. \"Yep\". 'Yep'.",
|
||||
"xss": "<script>alert(\"uh oh\");</script>",
|
||||
"intmap": map[int]string{
|
||||
1: "one",
|
||||
2: "two",
|
||||
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 {
|
||||
return a + b
|
||||
|
@ -167,17 +158,17 @@ Yep!`,
|
|||
}
|
||||
return s
|
||||
},
|
||||
"func_variadic_sum_int2": func(args ...*Value) *Value {
|
||||
"func_variadic_sum_int2": func(args ...*pongo2.Value) *pongo2.Value {
|
||||
// Create a sum
|
||||
s := 0
|
||||
for _, i := range args {
|
||||
s += i.Integer()
|
||||
}
|
||||
return AsValue(s)
|
||||
return pongo2.AsValue(s)
|
||||
},
|
||||
},
|
||||
"complex": map[string]interface{}{
|
||||
"is_admin": is_admin,
|
||||
"is_admin": isAdmin,
|
||||
"post": post{
|
||||
Text: "<h2>Hello!</h2><p>Welcome to my new blog page. I'm using pongo2 which supports {{ variables }} and {% tags %}.</p>",
|
||||
Created: time2,
|
||||
|
@ -238,10 +229,8 @@ Yep!`,
|
|||
}
|
||||
|
||||
func TestTemplates(t *testing.T) {
|
||||
debug = true
|
||||
|
||||
// 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")
|
||||
if err != nil {
|
||||
|
@ -249,34 +238,34 @@ func TestTemplates(t *testing.T) {
|
|||
}
|
||||
for idx, match := range matches {
|
||||
t.Logf("[Template %3d] Testing '%s'", idx+1, match)
|
||||
tpl, err := FromFile(match)
|
||||
tpl, err := pongo2.FromFile(match)
|
||||
if err != nil {
|
||||
t.Fatalf("Error on FromFile('%s'): %s", match, err.Error())
|
||||
}
|
||||
test_filename := fmt.Sprintf("%s.out", match)
|
||||
test_out, rerr := ioutil.ReadFile(test_filename)
|
||||
testFilename := fmt.Sprintf("%s.out", match)
|
||||
testOut, rerr := ioutil.ReadFile(testFilename)
|
||||
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 {
|
||||
t.Fatalf("Error on Execute('%s'): %s", match, err.Error())
|
||||
}
|
||||
if bytes.Compare(test_out, tpl_out) != 0 {
|
||||
t.Logf("Template (rendered) '%s': '%s'", match, tpl_out)
|
||||
err_filename := filepath.Base(fmt.Sprintf("%s.error", match))
|
||||
err := ioutil.WriteFile(err_filename, []byte(tpl_out), 0600)
|
||||
if bytes.Compare(testOut, tplOut) != 0 {
|
||||
t.Logf("Template (rendered) '%s': '%s'", match, tplOut)
|
||||
errFilename := filepath.Base(fmt.Sprintf("%s.error", match))
|
||||
err := ioutil.WriteFile(errFilename, []byte(tplOut), 0600)
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutionErrors(t *testing.T) {
|
||||
debug = true
|
||||
//debug = true
|
||||
|
||||
matches, err := filepath.Glob("./template_tests/*-execution.err")
|
||||
if err != nil {
|
||||
|
@ -285,15 +274,15 @@ func TestExecutionErrors(t *testing.T) {
|
|||
for idx, match := range matches {
|
||||
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
||||
|
||||
test_data, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(test_data), "\n")
|
||||
testData, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(testData), "\n")
|
||||
|
||||
check_filename := fmt.Sprintf("%s.out", match)
|
||||
check_data, err := ioutil.ReadFile(check_filename)
|
||||
checkFilename := fmt.Sprintf("%s.out", match)
|
||||
checkData, err := ioutil.ReadFile(checkFilename)
|
||||
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) {
|
||||
t.Fatal("Template lines != Checks lines")
|
||||
|
@ -308,11 +297,16 @@ func TestExecutionErrors(t *testing.T) {
|
|||
match, idx+1)
|
||||
}
|
||||
|
||||
tpl, err := FromString(test)
|
||||
tpl, err := pongo2.FromString(test)
|
||||
if err != nil {
|
||||
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)
|
||||
if err == nil {
|
||||
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) {
|
||||
debug = true
|
||||
//debug = true
|
||||
|
||||
matches, err := filepath.Glob("./template_tests/*-compilation.err")
|
||||
if err != nil {
|
||||
|
@ -338,15 +332,15 @@ func TestCompilationErrors(t *testing.T) {
|
|||
for idx, match := range matches {
|
||||
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
||||
|
||||
test_data, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(test_data), "\n")
|
||||
testData, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(testData), "\n")
|
||||
|
||||
check_filename := fmt.Sprintf("%s.out", match)
|
||||
check_data, err := ioutil.ReadFile(check_filename)
|
||||
checkFilename := fmt.Sprintf("%s.out", match)
|
||||
checkData, err := ioutil.ReadFile(checkFilename)
|
||||
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) {
|
||||
t.Fatal("Template lines != Checks lines")
|
||||
|
@ -361,7 +355,7 @@ func TestCompilationErrors(t *testing.T) {
|
|||
match, idx+1)
|
||||
}
|
||||
|
||||
_, err = FromString(test)
|
||||
_, err = pongo2.FromString(test)
|
||||
if err == nil {
|
||||
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) {
|
||||
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/"
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -405,13 +400,13 @@ func TestBaseDirectory(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkCache(b *testing.B) {
|
||||
cache_set := NewSet("cache set")
|
||||
cacheSet := pongo2.NewSet("cache set", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
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 {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -419,14 +414,14 @@ func BenchmarkCache(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkCacheDebugOn(b *testing.B) {
|
||||
cache_debug_set := NewSet("cache set")
|
||||
cache_debug_set.Debug = true
|
||||
cacheDebugSet := pongo2.NewSet("cache set", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
cacheDebugSet.Debug = true
|
||||
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 {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -434,13 +429,13 @@ func BenchmarkCacheDebugOn(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 {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -455,12 +450,12 @@ func BenchmarkCompileAndExecuteComplexWithSandboxActive(b *testing.B) {
|
|||
preloadedTpl := string(buf)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tpl, err := FromString(preloadedTpl)
|
||||
tpl, err := pongo2.FromString(preloadedTpl)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -468,14 +463,14 @@ func BenchmarkCompileAndExecuteComplexWithSandboxActive(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 {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, err := tpl.ExecuteBytes(tplContext)
|
||||
err := tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -484,14 +479,14 @@ func BenchmarkParallelExecuteComplexWithSandboxActive(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")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -505,7 +500,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
|||
}
|
||||
preloadedTpl := string(buf)
|
||||
|
||||
s := NewSet("set without sandbox")
|
||||
s := pongo2.NewSet("set without sandbox", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -514,7 +509,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
|||
b.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -522,7 +517,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(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")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
|
@ -530,7 +525,7 @@ func BenchmarkParallelExecuteComplexWithoutSandbox(b *testing.B) {
|
|||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, err := tpl.ExecuteBytes(tplContext)
|
||||
err := tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
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 (
|
||||
"testing"
|
||||
|
||||
"github.com/flosch/pongo2"
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
// Hook up gocheck into the "go test" runner.
|
||||
|
||||
func Test(t *testing.T) { TestingT(t) }
|
||||
|
||||
type TestSuite struct {
|
||||
tpl *Template
|
||||
tpl *pongo2.Template
|
||||
}
|
||||
|
||||
var (
|
||||
_ = Suite(&TestSuite{})
|
||||
test_suite2 = NewSet("test suite 2")
|
||||
testSuite2 = pongo2.NewSet("test suite 2", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
)
|
||||
|
||||
func parseTemplate(s string, c Context) string {
|
||||
t, err := test_suite2.FromString(s)
|
||||
func parseTemplate(s string, c pongo2.Context) string {
|
||||
t, err := testSuite2.FromString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func parseTemplate(s string, c Context) string {
|
|||
return out
|
||||
}
|
||||
|
||||
func parseTemplateFn(s string, c Context) func() {
|
||||
func parseTemplateFn(s string, c pongo2.Context) func() {
|
||||
return func() {
|
||||
parseTemplate(s, c)
|
||||
}
|
||||
|
@ -40,27 +40,64 @@ func parseTemplateFn(s string, c Context) func() {
|
|||
func (s *TestSuite) TestMisc(c *C) {
|
||||
// Must
|
||||
// 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,
|
||||
`\[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
|
||||
c.Check(parseTemplateFn("", Context{"'illegal": nil}), PanicMatches, ".*not a valid identifier.*")
|
||||
c.Check(parseTemplateFn("", pongo2.Context{"'illegal": nil}), PanicMatches, ".*not a valid identifier.*")
|
||||
|
||||
// Registers
|
||||
c.Check(func() { RegisterFilter("escape", nil) }, PanicMatches, ".*is already registered.*")
|
||||
c.Check(func() { RegisterTag("for", nil) }, PanicMatches, ".*is already registered.*")
|
||||
c.Check(pongo2.RegisterFilter("escape", nil).Error(), Matches, ".*is already registered")
|
||||
c.Check(pongo2.RegisterTag("for", nil).Error(), Matches, ".*is already registered")
|
||||
|
||||
// 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 {
|
||||
c.Fatal(err)
|
||||
}
|
||||
c.Check(v.String(), Equals, "This Is A Title")
|
||||
c.Check(func() {
|
||||
_, err := ApplyFilter("doesnotexist", nil, nil)
|
||||
_, err := pongo2.ApplyFilter("doesnotexist", nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}, 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type INodeTag interface {
|
||||
|
@ -53,80 +55,81 @@ func init() {
|
|||
tags = make(map[string]*tag)
|
||||
}
|
||||
|
||||
// Registers a new tag. If there's already a tag with the same
|
||||
// name, RegisterTag will panic. You usually want to call this
|
||||
// Registers a new tag. You usually want to call this
|
||||
// function in the tag's init() function:
|
||||
// http://golang.org/doc/effective_go.html#init
|
||||
//
|
||||
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
||||
// writing filters and tags.
|
||||
func RegisterTag(name string, parserFn TagParser) {
|
||||
func RegisterTag(name string, parserFn TagParser) error {
|
||||
_, existing := tags[name]
|
||||
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{
|
||||
name: name,
|
||||
parser: parserFn,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replaces an already registered tag with a new implementation. Use this
|
||||
// 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]
|
||||
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{
|
||||
name: name,
|
||||
parser: parserFn,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tag = "{%" IDENT ARGS "%}"
|
||||
func (p *Parser) parseTagElement() (INodeTag, *Error) {
|
||||
p.Consume() // consume "{%"
|
||||
token_name := p.MatchType(TokenIdentifier)
|
||||
tokenName := p.MatchType(TokenIdentifier)
|
||||
|
||||
// Check for identifier
|
||||
if token_name == nil {
|
||||
if tokenName == nil {
|
||||
return nil, p.Error("Tag name must be an identifier.", nil)
|
||||
}
|
||||
|
||||
// Check for the existing tag
|
||||
tag, exists := tags[token_name.Val]
|
||||
tag, exists := tags[tokenName.Val]
|
||||
if !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
|
||||
if _, is_banned := p.template.set.bannedTags[token_name.Val]; is_banned {
|
||||
return nil, p.Error(fmt.Sprintf("Usage of tag '%s' is not allowed (sandbox restriction active).", token_name.Val), token_name)
|
||||
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).", tokenName.Val), tokenName)
|
||||
}
|
||||
|
||||
args_token := make([]*Token, 0)
|
||||
var argsToken []*Token
|
||||
for p.Peek(TokenSymbol, "%}") == nil && p.Remaining() > 0 {
|
||||
// Add token to args
|
||||
args_token = append(args_token, p.Current())
|
||||
argsToken = append(argsToken, p.Current())
|
||||
p.Consume() // next token
|
||||
}
|
||||
|
||||
// EOF?
|
||||
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, "%}")
|
||||
|
||||
arg_parser := newParser(p.name, args_token, p.template)
|
||||
if len(args_token) == 0 {
|
||||
argParser := newParser(p.name, argsToken, p.template)
|
||||
if len(argsToken) == 0 {
|
||||
// This is done to have nice EOF error messages
|
||||
arg_parser.last_token = token_name
|
||||
argParser.lastToken = tokenName
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagAutoescapeNode struct {
|
||||
wrapper *NodeWrapper
|
||||
autoescape bool
|
||||
}
|
||||
|
||||
func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
old := ctx.Autoescape
|
||||
ctx.Autoescape = node.autoescape
|
||||
|
||||
err := node.wrapper.Execute(ctx, buffer)
|
||||
err := node.wrapper.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
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) {
|
||||
autoescape_node := &tagAutoescapeNode{}
|
||||
autoescapeNode := &tagAutoescapeNode{}
|
||||
|
||||
wrapper, _, err := doc.WrapUntilTag("endautoescape")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
autoescape_node.wrapper = wrapper
|
||||
autoescapeNode.wrapper = wrapper
|
||||
|
||||
mode_token := arguments.MatchType(TokenIdentifier)
|
||||
if mode_token == nil {
|
||||
modeToken := arguments.MatchType(TokenIdentifier)
|
||||
if modeToken == nil {
|
||||
return nil, arguments.Error("A mode is required for autoescape-tag.", nil)
|
||||
}
|
||||
if mode_token.Val == "on" {
|
||||
autoescape_node.autoescape = true
|
||||
} else if mode_token.Val == "off" {
|
||||
autoescape_node.autoescape = false
|
||||
if modeToken.Val == "on" {
|
||||
autoescapeNode.autoescape = true
|
||||
} else if modeToken.Val == "off" {
|
||||
autoescapeNode.autoescape = false
|
||||
} else {
|
||||
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 autoescape_node, nil
|
||||
return autoescapeNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (node *tagBlockNode) getBlockWrapperByName(tpl *Template) *NodeWrapper {
|
||||
func (node *tagBlockNode) getBlockWrappers(tpl *Template) []*NodeWrapper {
|
||||
nodeWrappers := make([]*NodeWrapper, 0)
|
||||
var t *NodeWrapper
|
||||
if tpl.child != nil {
|
||||
// First ask the child for the block
|
||||
t = node.getBlockWrapperByName(tpl.child)
|
||||
}
|
||||
if t == nil {
|
||||
// Child has no block, lets look up here at parent
|
||||
|
||||
for tpl != nil {
|
||||
t = tpl.blocks[node.name]
|
||||
if t != nil {
|
||||
nodeWrappers = append(nodeWrappers, t)
|
||||
}
|
||||
return t
|
||||
tpl = tpl.child
|
||||
}
|
||||
|
||||
func (node *tagBlockNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
return nodeWrappers
|
||||
}
|
||||
|
||||
func (node *tagBlockNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
tpl := ctx.template
|
||||
if tpl == nil {
|
||||
panic("internal error: tpl == nil")
|
||||
}
|
||||
|
||||
// Determine the block to execute
|
||||
block_wrapper := node.getBlockWrapperByName(tpl)
|
||||
if block_wrapper == nil {
|
||||
// fmt.Printf("could not find: %s\n", node.name)
|
||||
return ctx.Error("internal error: block_wrapper == nil in tagBlockNode.Execute()", nil)
|
||||
blockWrappers := node.getBlockWrappers(tpl)
|
||||
lenBlockWrappers := len(blockWrappers)
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Add support for {{ block.super }}
|
||||
|
||||
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) {
|
||||
if arguments.Count() == 0 {
|
||||
return nil, arguments.Error("Tag 'block' requires an identifier.", nil)
|
||||
}
|
||||
|
||||
name_token := arguments.MatchType(TokenIdentifier)
|
||||
if name_token == nil {
|
||||
nameToken := arguments.MatchType(TokenIdentifier)
|
||||
if nameToken == 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
|
||||
}
|
||||
if endtagargs.Remaining() > 0 {
|
||||
endtagname_token := endtagargs.MatchType(TokenIdentifier)
|
||||
if endtagname_token != nil {
|
||||
if endtagname_token.Val != name_token.Val {
|
||||
endtagnameToken := endtagargs.MatchType(TokenIdentifier)
|
||||
if endtagnameToken != nil {
|
||||
if endtagnameToken.Val != nameToken.Val {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -79,14 +114,14 @@ func tagBlockParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
|||
if tpl == nil {
|
||||
panic("internal error: tpl == nil")
|
||||
}
|
||||
_, has_block := tpl.blocks[name_token.Val]
|
||||
if !has_block {
|
||||
tpl.blocks[name_token.Val] = wrapper
|
||||
_, hasBlock := tpl.blocks[nameToken.Val]
|
||||
if !hasBlock {
|
||||
tpl.blocks[nameToken.Val] = wrapper
|
||||
} 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() {
|
||||
|
|
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagCommentNode struct{}
|
||||
|
||||
func (node *tagCommentNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagCommentNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
_, _, err := doc.WrapUntilTag("endcomment")
|
||||
err := doc.SkipUntilTag("endcomment")
|
||||
if err != nil {
|
||||
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 comment_node, nil
|
||||
return commentNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagCycleValue struct {
|
||||
node *tagCycleNode
|
||||
value *Value
|
||||
|
@ -13,7 +9,7 @@ type tagCycleNode struct {
|
|||
position *Token
|
||||
args []IEvaluator
|
||||
idx int
|
||||
as_name string
|
||||
asName string
|
||||
silent bool
|
||||
}
|
||||
|
||||
|
@ -21,7 +17,7 @@ func (cv *tagCycleValue) String() 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)]
|
||||
node.idx++
|
||||
|
||||
|
@ -46,30 +42,30 @@ func (node *tagCycleNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *
|
|||
t.value = val
|
||||
|
||||
if !t.node.silent {
|
||||
buffer.WriteString(val.String())
|
||||
writer.WriteString(val.String())
|
||||
}
|
||||
} else {
|
||||
// Regular call
|
||||
|
||||
cycle_value := &tagCycleValue{
|
||||
cycleValue := &tagCycleValue{
|
||||
node: node,
|
||||
value: val,
|
||||
}
|
||||
|
||||
if node.as_name != "" {
|
||||
ctx.Private[node.as_name] = cycle_value
|
||||
if node.asName != "" {
|
||||
ctx.Private[node.asName] = cycleValue
|
||||
}
|
||||
if !node.silent {
|
||||
buffer.WriteString(val.String())
|
||||
writer.WriteString(val.String())
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
cycle_node := &tagCycleNode{
|
||||
cycleNode := &tagCycleNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
|
@ -78,19 +74,19 @@ func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cycle_node.args = append(cycle_node.args, node)
|
||||
cycleNode.args = append(cycleNode.args, node)
|
||||
|
||||
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
||||
// as
|
||||
|
||||
name_token := arguments.MatchType(TokenIdentifier)
|
||||
if name_token == nil {
|
||||
nameToken := arguments.MatchType(TokenIdentifier)
|
||||
if nameToken == 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 {
|
||||
cycle_node.silent = true
|
||||
cycleNode.silent = true
|
||||
}
|
||||
|
||||
// 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 cycle_node, nil
|
||||
return cycleNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagExtendsNode struct {
|
||||
filename string
|
||||
}
|
||||
|
||||
func (node *tagExtendsNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagExtendsNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
extends_node := &tagExtendsNode{}
|
||||
extendsNode := &tagExtendsNode{}
|
||||
|
||||
if doc.template.level > 1 {
|
||||
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)
|
||||
}
|
||||
|
||||
if filename_token := arguments.MatchType(TokenString); filename_token != nil {
|
||||
if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
|
||||
// prepared, static template
|
||||
|
||||
// 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
|
||||
parent_template, err := doc.template.set.FromFile(parent_filename)
|
||||
parentTemplate, err := doc.template.set.FromFile(parentFilename)
|
||||
if err != nil {
|
||||
return nil, err.(*Error)
|
||||
}
|
||||
|
||||
// Keep track of things
|
||||
parent_template.child = doc.template
|
||||
doc.template.parent = parent_template
|
||||
extends_node.filename = parent_filename
|
||||
parentTemplate.child = doc.template
|
||||
doc.template.parent = parentTemplate
|
||||
extendsNode.filename = parentFilename
|
||||
} else {
|
||||
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 extends_node, nil
|
||||
return extendsNode, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
name string
|
||||
param_expr IEvaluator
|
||||
paramExpr IEvaluator
|
||||
}
|
||||
|
||||
type tagFilterNode struct {
|
||||
|
@ -15,7 +15,7 @@ type tagFilterNode struct {
|
|||
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
|
||||
|
||||
err := node.bodyWrapper.Execute(ctx, temp)
|
||||
|
@ -27,8 +27,8 @@ func (node *tagFilterNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
|
||||
for _, call := range node.filterChain {
|
||||
var param *Value
|
||||
if call.param_expr != nil {
|
||||
param, err = call.param_expr.Evaluate(ctx)
|
||||
if call.paramExpr != nil {
|
||||
param, err = call.paramExpr.Evaluate(ctx)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
filter_node := &tagFilterNode{
|
||||
filterNode := &tagFilterNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
|
@ -55,16 +55,16 @@ func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter_node.bodyWrapper = wrapper
|
||||
filterNode.bodyWrapper = wrapper
|
||||
|
||||
for arguments.Remaining() > 0 {
|
||||
filterCall := &nodeFilterCall{}
|
||||
|
||||
name_token := arguments.MatchType(TokenIdentifier)
|
||||
if name_token == nil {
|
||||
nameToken := arguments.MatchType(TokenIdentifier)
|
||||
if nameToken == 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 {
|
||||
// Filter parameter
|
||||
|
@ -73,10 +73,10 @@ func tagFilterParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
|||
if err != nil {
|
||||
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 {
|
||||
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 filter_node, nil
|
||||
return filterNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagFirstofNode struct {
|
||||
position *Token
|
||||
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 {
|
||||
val, err := arg.Evaluate(ctx)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +29,7 @@ func (node *tagFirstofNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
}
|
||||
|
||||
func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
firstof_node := &tagFirstofNode{
|
||||
firstofNode := &tagFirstofNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
|
@ -42,10 +38,10 @@ func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
if err != nil {
|
||||
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() {
|
||||
|
|
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagForNode struct {
|
||||
key string
|
||||
value string // only for maps: for key, value in map
|
||||
object_evaluator IEvaluator
|
||||
objectEvaluator IEvaluator
|
||||
reversed bool
|
||||
sorted bool
|
||||
|
||||
bodyWrapper *NodeWrapper
|
||||
emptyWrapper *NodeWrapper
|
||||
|
@ -24,7 +21,7 @@ type tagForLoopInformation struct {
|
|||
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
|
||||
forCtx := NewChildExecutionContext(ctx)
|
||||
parentloop := forCtx.Private["forloop"]
|
||||
|
@ -42,7 +39,7 @@ func (node *tagForNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) (fo
|
|||
// Register loopInfo in public context
|
||||
forCtx.Private["forloop"] = loopInfo
|
||||
|
||||
obj, err := node.object_evaluator.Evaluate(forCtx)
|
||||
obj, err := node.objectEvaluator.Evaluate(forCtx)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
// Render elements with updated context
|
||||
err := node.bodyWrapper.Execute(forCtx, buffer)
|
||||
err := node.bodyWrapper.Execute(forCtx, writer)
|
||||
if err != nil {
|
||||
forError = err
|
||||
return false
|
||||
|
@ -76,30 +73,30 @@ func (node *tagForNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) (fo
|
|||
}, func() {
|
||||
// Nothing to iterate over (maybe wrong type or no items)
|
||||
if node.emptyWrapper != nil {
|
||||
err := node.emptyWrapper.Execute(forCtx, buffer)
|
||||
err := node.emptyWrapper.Execute(forCtx, writer)
|
||||
if err != nil {
|
||||
forError = err
|
||||
}
|
||||
}
|
||||
}, node.reversed)
|
||||
}, node.reversed, node.sorted)
|
||||
|
||||
return nil
|
||||
return forError
|
||||
}
|
||||
|
||||
func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
for_node := &tagForNode{}
|
||||
forNode := &tagForNode{}
|
||||
|
||||
// Arguments parsing
|
||||
var value_token *Token
|
||||
key_token := arguments.MatchType(TokenIdentifier)
|
||||
if key_token == nil {
|
||||
var valueToken *Token
|
||||
keyToken := arguments.MatchType(TokenIdentifier)
|
||||
if keyToken == nil {
|
||||
return nil, arguments.Error("Expected an key identifier as first argument for 'for'-tag", nil)
|
||||
}
|
||||
|
||||
if arguments.Match(TokenSymbol, ",") != nil {
|
||||
// Value name is provided
|
||||
value_token = arguments.MatchType(TokenIdentifier)
|
||||
if value_token == nil {
|
||||
valueToken = arguments.MatchType(TokenIdentifier)
|
||||
if valueToken == 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)
|
||||
}
|
||||
|
||||
object_evaluator, err := arguments.ParseExpression()
|
||||
objectEvaluator, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for_node.object_evaluator = object_evaluator
|
||||
for_node.key = key_token.Val
|
||||
if value_token != nil {
|
||||
for_node.value = value_token.Val
|
||||
forNode.objectEvaluator = objectEvaluator
|
||||
forNode.key = keyToken.Val
|
||||
if valueToken != nil {
|
||||
forNode.value = valueToken.Val
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -131,7 +132,7 @@ func tagForParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Erro
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for_node.bodyWrapper = wrapper
|
||||
forNode.bodyWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
for_node.emptyWrapper = wrapper
|
||||
forNode.emptyWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return for_node, nil
|
||||
return forNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIfNode struct {
|
||||
conditions []IEvaluator
|
||||
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 {
|
||||
result, err := condition.Evaluate(ctx)
|
||||
if err != nil {
|
||||
|
@ -17,26 +13,25 @@ func (node *tagIfNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Err
|
|||
}
|
||||
|
||||
if result.IsTrue() {
|
||||
return node.wrappers[i].Execute(ctx, buffer)
|
||||
} else {
|
||||
return node.wrappers[i].Execute(ctx, writer)
|
||||
}
|
||||
// Last condition?
|
||||
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
|
||||
}
|
||||
|
||||
func tagIfParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
if_node := &tagIfNode{}
|
||||
ifNode := &tagIfNode{}
|
||||
|
||||
// Parse first and main IF condition
|
||||
condition, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if_node.conditions = append(if_node.conditions, condition)
|
||||
ifNode.conditions = append(ifNode.conditions, condition)
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
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
|
||||
for {
|
||||
wrapper, tag_args, err := doc.WrapUntilTag("elif", "else", "endif")
|
||||
wrapper, tagArgs, err := doc.WrapUntilTag("elif", "else", "endif")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if_node.wrappers = append(if_node.wrappers, wrapper)
|
||||
ifNode.wrappers = append(ifNode.wrappers, wrapper)
|
||||
|
||||
if wrapper.Endtag == "elif" {
|
||||
// elif can take a condition
|
||||
condition, err := tag_args.ParseExpression()
|
||||
condition, err = tagArgs.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if_node.conditions = append(if_node.conditions, condition)
|
||||
ifNode.conditions = append(ifNode.conditions, condition)
|
||||
|
||||
if tag_args.Remaining() > 0 {
|
||||
return nil, tag_args.Error("Elif-condition is malformed.", nil)
|
||||
if tagArgs.Remaining() > 0 {
|
||||
return nil, tagArgs.Error("Elif-condition is malformed.", nil)
|
||||
}
|
||||
} else {
|
||||
if tag_args.Count() > 0 {
|
||||
if tagArgs.Count() > 0 {
|
||||
// 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() {
|
||||
|
|
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 {
|
||||
watched_expr []IEvaluator
|
||||
last_values []*Value
|
||||
last_content []byte
|
||||
watchedExpr []IEvaluator
|
||||
lastValues []*Value
|
||||
lastContent []byte
|
||||
thenWrapper *NodeWrapper
|
||||
elseWrapper *NodeWrapper
|
||||
}
|
||||
|
||||
func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
|
||||
if len(node.watched_expr) == 0 {
|
||||
func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
if len(node.watchedExpr) == 0 {
|
||||
// Check against own rendered body
|
||||
|
||||
buf := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
|
||||
|
@ -23,43 +22,43 @@ func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffe
|
|||
return err
|
||||
}
|
||||
|
||||
buf_bytes := buf.Bytes()
|
||||
if !bytes.Equal(node.last_content, buf_bytes) {
|
||||
bufBytes := buf.Bytes()
|
||||
if !bytes.Equal(node.lastContent, bufBytes) {
|
||||
// Rendered content changed, output it
|
||||
buffer.Write(buf_bytes)
|
||||
node.last_content = buf_bytes
|
||||
writer.Write(bufBytes)
|
||||
node.lastContent = bufBytes
|
||||
}
|
||||
} else {
|
||||
now_values := make([]*Value, 0, len(node.watched_expr))
|
||||
for _, expr := range node.watched_expr {
|
||||
nowValues := make([]*Value, 0, len(node.watchedExpr))
|
||||
for _, expr := range node.watchedExpr {
|
||||
val, err := expr.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
now_values = append(now_values, val)
|
||||
nowValues = append(nowValues, val)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if !old_val.EqualValueTo(now_values[idx]) {
|
||||
for idx, oldVal := range node.lastValues {
|
||||
if !oldVal.EqualValueTo(nowValues[idx]) {
|
||||
changed = true
|
||||
break // we can stop here because ONE value changed
|
||||
}
|
||||
}
|
||||
|
||||
node.last_values = now_values
|
||||
node.lastValues = nowValues
|
||||
|
||||
if changed {
|
||||
// Render thenWrapper
|
||||
err := node.thenWrapper.Execute(ctx, buffer)
|
||||
err := node.thenWrapper.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Render elseWrapper
|
||||
err := node.elseWrapper.Execute(ctx, buffer)
|
||||
err := node.elseWrapper.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
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) {
|
||||
ifchanged_node := &tagIfchangedNode{}
|
||||
ifchangedNode := &tagIfchangedNode{}
|
||||
|
||||
for arguments.Remaining() > 0 {
|
||||
// Parse condition
|
||||
|
@ -78,7 +77,7 @@ func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifchanged_node.watched_expr = append(ifchanged_node.watched_expr, expr)
|
||||
ifchangedNode.watchedExpr = append(ifchangedNode.watchedExpr, expr)
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
|
@ -90,7 +89,7 @@ func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifchanged_node.thenWrapper = wrapper
|
||||
ifchangedNode.thenWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
ifchanged_node.elseWrapper = wrapper
|
||||
ifchangedNode.elseWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return ifchanged_node, nil
|
||||
return ifchangedNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIfEqualNode struct {
|
||||
var1, var2 IEvaluator
|
||||
thenWrapper *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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -23,17 +19,16 @@ func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
result := r1.EqualValueTo(r2)
|
||||
|
||||
if result {
|
||||
return node.thenWrapper.Execute(ctx, buffer)
|
||||
} else {
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, buffer)
|
||||
return node.thenWrapper.Execute(ctx, writer)
|
||||
}
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, writer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
ifequal_node := &tagIfEqualNode{}
|
||||
ifequalNode := &tagIfEqualNode{}
|
||||
|
||||
// Parse two expressions
|
||||
var1, err := arguments.ParseExpression()
|
||||
|
@ -44,8 +39,8 @@ func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifequal_node.var1 = var1
|
||||
ifequal_node.var2 = var2
|
||||
ifequalNode.var1 = var1
|
||||
ifequalNode.var2 = var2
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
ifequal_node.thenWrapper = wrapper
|
||||
ifequalNode.thenWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
ifequal_node.elseWrapper = wrapper
|
||||
ifequalNode.elseWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return ifequal_node, nil
|
||||
return ifequalNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIfNotEqualNode struct {
|
||||
var1, var2 IEvaluator
|
||||
thenWrapper *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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -23,17 +19,16 @@ func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buff
|
|||
result := !r1.EqualValueTo(r2)
|
||||
|
||||
if result {
|
||||
return node.thenWrapper.Execute(ctx, buffer)
|
||||
} else {
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, buffer)
|
||||
return node.thenWrapper.Execute(ctx, writer)
|
||||
}
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, writer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
ifnotequal_node := &tagIfNotEqualNode{}
|
||||
ifnotequalNode := &tagIfNotEqualNode{}
|
||||
|
||||
// Parse two expressions
|
||||
var1, err := arguments.ParseExpression()
|
||||
|
@ -44,19 +39,19 @@ func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifnotequal_node.var1 = var1
|
||||
ifnotequal_node.var2 = var2
|
||||
ifnotequalNode.var1 = var1
|
||||
ifnotequalNode.var2 = var2
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
|
||||
}
|
||||
|
||||
// Wrap then/else-blocks
|
||||
wrapper, endargs, err := doc.WrapUntilTag("else", "endifequal")
|
||||
wrapper, endargs, err := doc.WrapUntilTag("else", "endifnotequal")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifnotequal_node.thenWrapper = wrapper
|
||||
ifnotequalNode.thenWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
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 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 {
|
||||
return nil, err
|
||||
}
|
||||
ifnotequal_node.elseWrapper = wrapper
|
||||
ifnotequalNode.elseWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return ifnotequal_node, nil
|
||||
return ifnotequalNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type tagImportNode struct {
|
||||
position *Token
|
||||
filename string
|
||||
template *Template
|
||||
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 {
|
||||
func(name string, macro *tagMacroNode) {
|
||||
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) {
|
||||
import_node := &tagImportNode{
|
||||
importNode := &tagImportNode{
|
||||
position: start,
|
||||
macros: make(map[string]*tagMacroNode),
|
||||
}
|
||||
|
||||
filename_token := arguments.MatchType(TokenString)
|
||||
if filename_token == nil {
|
||||
filenameToken := arguments.MatchType(TokenString)
|
||||
if filenameToken == 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 {
|
||||
return nil, arguments.Error("You must at least specify one macro to import.", nil)
|
||||
}
|
||||
|
||||
// Compile the given template
|
||||
tpl, err := doc.template.set.FromFile(import_node.filename)
|
||||
tpl, err := doc.template.set.FromFile(importNode.filename)
|
||||
if err != nil {
|
||||
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, start)
|
||||
}
|
||||
|
||||
for arguments.Remaining() > 0 {
|
||||
macro_name_token := arguments.MatchType(TokenIdentifier)
|
||||
if macro_name_token == nil {
|
||||
macroNameToken := arguments.MatchType(TokenIdentifier)
|
||||
if macroNameToken == 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 {
|
||||
alias_token := arguments.MatchType(TokenIdentifier)
|
||||
if alias_token == nil {
|
||||
aliasToken := arguments.MatchType(TokenIdentifier)
|
||||
if aliasToken == 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 {
|
||||
return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macro_name_token.Val,
|
||||
import_node.filename), macro_name_token)
|
||||
return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macroNameToken.Val,
|
||||
importNode.filename), macroNameToken)
|
||||
}
|
||||
|
||||
import_node.macros[as_name] = macro_instance
|
||||
importNode.macros[asName] = macroInstance
|
||||
|
||||
if arguments.Remaining() == 0 {
|
||||
break
|
||||
|
@ -78,7 +76,7 @@ func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
|||
}
|
||||
}
|
||||
|
||||
return import_node, nil
|
||||
return importNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
88
vendor/github.com/flosch/pongo2/tags_include.go
generated
vendored
88
vendor/github.com/flosch/pongo2/tags_include.go
generated
vendored
|
@ -1,41 +1,38 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIncludeNode struct {
|
||||
tpl *Template
|
||||
filename_evaluator IEvaluator
|
||||
filenameEvaluator IEvaluator
|
||||
lazy bool
|
||||
only bool
|
||||
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
|
||||
include_ctx := make(Context)
|
||||
includeCtx := make(Context)
|
||||
|
||||
// Fill the context with all data from the parent
|
||||
if !node.only {
|
||||
include_ctx.Update(ctx.Public)
|
||||
include_ctx.Update(ctx.Private)
|
||||
includeCtx.Update(ctx.Public)
|
||||
includeCtx.Update(ctx.Private)
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
include_ctx[key] = val
|
||||
includeCtx[key] = val
|
||||
}
|
||||
|
||||
// Execute the template
|
||||
if node.lazy {
|
||||
// Evaluate the filename
|
||||
filename, err := node.filename_evaluator.Evaluate(ctx)
|
||||
filename, err := node.filenameEvaluator.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -45,76 +42,93 @@ func (node *tagIncludeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
}
|
||||
|
||||
// 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 this is ReadFile error, and "if_exists" flag is enabled
|
||||
if node.ifExists && err2.(*Error).Sender == "fromfile" {
|
||||
return nil
|
||||
}
|
||||
return err2.(*Error)
|
||||
}
|
||||
err2 = included_tpl.ExecuteWriter(include_ctx, buffer)
|
||||
err2 = includedTpl.ExecuteWriter(includeCtx, writer)
|
||||
if err2 != nil {
|
||||
return err2.(*Error)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
}
|
||||
// Template is already parsed with static filename
|
||||
err := node.tpl.ExecuteWriter(include_ctx, buffer)
|
||||
err := node.tpl.ExecuteWriter(includeCtx, writer)
|
||||
if err != nil {
|
||||
return err.(*Error)
|
||||
}
|
||||
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) {
|
||||
include_node := &tagIncludeNode{
|
||||
with_pairs: make(map[string]IEvaluator),
|
||||
includeNode := &tagIncludeNode{
|
||||
withPairs: make(map[string]IEvaluator),
|
||||
}
|
||||
|
||||
if filename_token := arguments.MatchType(TokenString); filename_token != nil {
|
||||
if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
|
||||
// prepared, static template
|
||||
|
||||
// "if_exists" flag
|
||||
ifExists := arguments.Match(TokenIdentifier, "if_exists") != nil
|
||||
|
||||
// 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
|
||||
include_node.filename = included_filename
|
||||
included_tpl, err := doc.template.set.FromFile(included_filename)
|
||||
includeNode.filename = includedFilename
|
||||
includedTpl, err := doc.template.set.FromFile(includedFilename)
|
||||
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 {
|
||||
// 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 {
|
||||
return nil, err.updateFromTokenIfNeeded(doc.template, filename_token)
|
||||
return nil, err.updateFromTokenIfNeeded(doc.template, filenameToken)
|
||||
}
|
||||
include_node.filename_evaluator = filename_evaluator
|
||||
include_node.lazy = true
|
||||
includeNode.filenameEvaluator = filenameEvaluator
|
||||
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
|
||||
if arguments.Match(TokenIdentifier, "with") != nil {
|
||||
for arguments.Remaining() > 0 {
|
||||
// We have at least one key=expr pair (because of starting "with")
|
||||
key_token := arguments.MatchType(TokenIdentifier)
|
||||
if key_token == nil {
|
||||
keyToken := arguments.MatchType(TokenIdentifier)
|
||||
if keyToken == nil {
|
||||
return nil, arguments.Error("Expected an identifier", nil)
|
||||
}
|
||||
if arguments.Match(TokenSymbol, "=") == nil {
|
||||
return nil, arguments.Error("Expected '='.", nil)
|
||||
}
|
||||
value_expr, err := arguments.ParseExpression()
|
||||
valueExpr, err := arguments.ParseExpression()
|
||||
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?
|
||||
if arguments.Match(TokenIdentifier, "only") != nil {
|
||||
include_node.only = true
|
||||
includeNode.only = true
|
||||
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 include_node, nil
|
||||
return includeNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -19,102 +20,102 @@ type tagLoremNode struct {
|
|||
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 {
|
||||
case "b":
|
||||
if node.random {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
||||
buffer.WriteString(par)
|
||||
writer.WriteString(par)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
||||
buffer.WriteString(par)
|
||||
writer.WriteString(par)
|
||||
}
|
||||
}
|
||||
case "w":
|
||||
if node.random {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString(" ")
|
||||
writer.WriteString(" ")
|
||||
}
|
||||
word := tagLoremWords[rand.Intn(len(tagLoremWords))]
|
||||
buffer.WriteString(word)
|
||||
writer.WriteString(word)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString(" ")
|
||||
writer.WriteString(" ")
|
||||
}
|
||||
word := tagLoremWords[i%len(tagLoremWords)]
|
||||
buffer.WriteString(word)
|
||||
writer.WriteString(word)
|
||||
}
|
||||
}
|
||||
case "p":
|
||||
if node.random {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
buffer.WriteString("<p>")
|
||||
writer.WriteString("<p>")
|
||||
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
||||
buffer.WriteString(par)
|
||||
buffer.WriteString("</p>")
|
||||
writer.WriteString(par)
|
||||
writer.WriteString("</p>")
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
buffer.WriteString("<p>")
|
||||
writer.WriteString("<p>")
|
||||
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
||||
buffer.WriteString(par)
|
||||
buffer.WriteString("</p>")
|
||||
writer.WriteString(par)
|
||||
writer.WriteString("</p>")
|
||||
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("unsupported method")
|
||||
return ctx.OrigError(errors.Errorf("unsupported method: %s", node.method), nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagLoremParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
lorem_node := &tagLoremNode{
|
||||
loremNode := &tagLoremNode{
|
||||
position: start,
|
||||
count: 1,
|
||||
method: "b",
|
||||
}
|
||||
|
||||
if count_token := arguments.MatchType(TokenNumber); count_token != nil {
|
||||
lorem_node.count = AsValue(count_token.Val).Integer()
|
||||
if countToken := arguments.MatchType(TokenNumber); countToken != nil {
|
||||
loremNode.count = AsValue(countToken.Val).Integer()
|
||||
}
|
||||
|
||||
if method_token := arguments.MatchType(TokenIdentifier); method_token != nil {
|
||||
if method_token.Val != "w" && method_token.Val != "p" && method_token.Val != "b" {
|
||||
if methodToken := arguments.MatchType(TokenIdentifier); methodToken != nil {
|
||||
if methodToken.Val != "w" && methodToken.Val != "p" && methodToken.Val != "b" {
|
||||
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 {
|
||||
lorem_node.random = true
|
||||
loremNode.random = true
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed lorem-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return lorem_node, nil
|
||||
return loremNode, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
position *Token
|
||||
name string
|
||||
args_order []string
|
||||
argsOrder []string
|
||||
args map[string]IEvaluator
|
||||
exported bool
|
||||
|
||||
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 {
|
||||
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 {
|
||||
args_ctx := make(Context)
|
||||
argsCtx := make(Context)
|
||||
|
||||
for k, v := range node.args {
|
||||
if v == nil {
|
||||
// User did not provided a default value
|
||||
args_ctx[k] = nil
|
||||
argsCtx[k] = nil
|
||||
} else {
|
||||
// Evaluate the default value
|
||||
value_expr, err := v.Evaluate(ctx)
|
||||
valueExpr, err := v.Evaluate(ctx)
|
||||
if err != nil {
|
||||
ctx.Logf(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.
|
||||
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
|
||||
return AsSafeValue(err.Error())
|
||||
|
@ -55,10 +55,10 @@ func (node *tagMacroNode) call(ctx *ExecutionContext, args ...*Value) *Value {
|
|||
macroCtx := NewChildExecutionContext(ctx)
|
||||
|
||||
// Register all arguments in the private context
|
||||
macroCtx.Private.Update(args_ctx)
|
||||
macroCtx.Private.Update(argsCtx)
|
||||
|
||||
for idx, arg_value := range args {
|
||||
macroCtx.Private[node.args_order[idx]] = arg_value.Interface()
|
||||
for idx, argValue := range args {
|
||||
macroCtx.Private[node.argsOrder[idx]] = argValue.Interface()
|
||||
}
|
||||
|
||||
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) {
|
||||
macro_node := &tagMacroNode{
|
||||
macroNode := &tagMacroNode{
|
||||
position: start,
|
||||
args: make(map[string]IEvaluator),
|
||||
}
|
||||
|
||||
name_token := arguments.MatchType(TokenIdentifier)
|
||||
if name_token == nil {
|
||||
nameToken := arguments.MatchType(TokenIdentifier)
|
||||
if nameToken == 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 {
|
||||
return nil, arguments.Error("Expected '('.", nil)
|
||||
}
|
||||
|
||||
for arguments.Match(TokenSymbol, ")") == nil {
|
||||
arg_name_token := arguments.MatchType(TokenIdentifier)
|
||||
if arg_name_token == nil {
|
||||
argNameToken := arguments.MatchType(TokenIdentifier)
|
||||
if argNameToken == 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 {
|
||||
// Default expression follows
|
||||
arg_default_expr, err := arguments.ParseExpression()
|
||||
argDefaultExpr, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
macro_node.args[arg_name_token.Val] = arg_default_expr
|
||||
macroNode.args[argNameToken.Val] = argDefaultExpr
|
||||
} else {
|
||||
// No default expression
|
||||
macro_node.args[arg_name_token.Val] = nil
|
||||
macroNode.args[argNameToken.Val] = 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 {
|
||||
macro_node.exported = true
|
||||
macroNode.exported = true
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
|
@ -126,22 +126,22 @@ func tagMacroParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
macro_node.wrapper = wrapper
|
||||
macroNode.wrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
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
|
||||
_, has := doc.template.exported_macros[macro_node.name]
|
||||
_, has := doc.template.exportedMacros[macroNode.name]
|
||||
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() {
|
||||
|
|
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -11,7 +10,7 @@ type tagNowNode struct {
|
|||
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
|
||||
if node.fake {
|
||||
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()
|
||||
}
|
||||
|
||||
buffer.WriteString(t.Format(node.format))
|
||||
writer.WriteString(t.Format(node.format))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagNowParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
now_node := &tagNowNode{
|
||||
nowNode := &tagNowNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
format_token := arguments.MatchType(TokenString)
|
||||
if format_token == nil {
|
||||
formatToken := arguments.MatchType(TokenString)
|
||||
if formatToken == 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 {
|
||||
now_node.fake = true
|
||||
nowNode.fake = true
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed now-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return now_node, nil
|
||||
return nowNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import "bytes"
|
||||
|
||||
type tagSetNode struct {
|
||||
name string
|
||||
expression IEvaluator
|
||||
}
|
||||
|
||||
func (node *tagSetNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagSetNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
// Evaluate expression
|
||||
value, err := node.expression.Evaluate(ctx)
|
||||
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:(<.*>))`)
|
||||
|
||||
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
|
||||
|
||||
err := node.wrapper.Execute(ctx, b)
|
||||
|
@ -28,25 +28,25 @@ func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffe
|
|||
s = s2
|
||||
}
|
||||
|
||||
buffer.WriteString(s)
|
||||
writer.WriteString(s)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagSpacelessParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
spaceless_node := &tagSpacelessNode{}
|
||||
spacelessNode := &tagSpacelessNode{}
|
||||
|
||||
wrapper, _, err := doc.WrapUntilTag("endspaceless")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spaceless_node.wrapper = wrapper
|
||||
spacelessNode.wrapper = wrapper
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed spaceless-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return spaceless_node, nil
|
||||
return spacelessNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
|
@ -11,47 +10,47 @@ type tagSSINode struct {
|
|||
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 {
|
||||
// Execute the template within the current context
|
||||
includeCtx := make(Context)
|
||||
includeCtx.Update(ctx.Public)
|
||||
includeCtx.Update(ctx.Private)
|
||||
|
||||
err := node.template.ExecuteWriter(includeCtx, buffer)
|
||||
err := node.template.execute(includeCtx, writer)
|
||||
if err != nil {
|
||||
return err.(*Error)
|
||||
}
|
||||
} else {
|
||||
// Just print out the content
|
||||
buffer.WriteString(node.content)
|
||||
writer.WriteString(node.content)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagSSIParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
ssi_node := &tagSSINode{}
|
||||
SSINode := &tagSSINode{}
|
||||
|
||||
if file_token := arguments.MatchType(TokenString); file_token != nil {
|
||||
ssi_node.filename = file_token.Val
|
||||
if fileToken := arguments.MatchType(TokenString); fileToken != nil {
|
||||
SSINode.filename = fileToken.Val
|
||||
|
||||
if arguments.Match(TokenIdentifier, "parsed") != nil {
|
||||
// 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 {
|
||||
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 {
|
||||
// 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 {
|
||||
return nil, (&Error{
|
||||
Sender: "tag:ssi",
|
||||
ErrorMsg: err.Error(),
|
||||
}).updateFromTokenIfNeeded(doc.template, file_token)
|
||||
OrigError: err,
|
||||
}).updateFromTokenIfNeeded(doc.template, fileToken)
|
||||
}
|
||||
ssi_node.content = string(buf)
|
||||
SSINode.content = string(buf)
|
||||
}
|
||||
} else {
|
||||
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 ssi_node, nil
|
||||
return SSINode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagTemplateTagNode struct {
|
||||
content string
|
||||
}
|
||||
|
@ -19,20 +15,20 @@ var templateTagMapping = map[string]string{
|
|||
"closecomment": "#}",
|
||||
}
|
||||
|
||||
func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
buffer.WriteString(node.content)
|
||||
func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
writer.WriteString(node.content)
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
tt_node := &tagTemplateTagNode{}
|
||||
ttNode := &tagTemplateTagNode{}
|
||||
|
||||
if arg_token := arguments.MatchType(TokenIdentifier); arg_token != nil {
|
||||
output, found := templateTagMapping[arg_token.Val]
|
||||
if argToken := arguments.MatchType(TokenIdentifier); argToken != nil {
|
||||
output, found := templateTagMapping[argToken.Val]
|
||||
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 {
|
||||
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 tt_node, nil
|
||||
return ttNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
@ -10,10 +9,10 @@ type tagWidthratioNode struct {
|
|||
position *Token
|
||||
current, max 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)
|
||||
if err != nil {
|
||||
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))
|
||||
|
||||
if node.ctx_name == "" {
|
||||
buffer.WriteString(fmt.Sprintf("%d", value))
|
||||
if node.ctxName == "" {
|
||||
writer.WriteString(fmt.Sprintf("%d", value))
|
||||
} else {
|
||||
ctx.Private[node.ctx_name] = value
|
||||
ctx.Private[node.ctxName] = value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
widthratio_node := &tagWidthratioNode{
|
||||
widthratioNode := &tagWidthratioNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
|
@ -49,34 +48,34 @@ func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
widthratio_node.current = current
|
||||
widthratioNode.current = current
|
||||
|
||||
max, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
widthratio_node.max = max
|
||||
widthratioNode.max = max
|
||||
|
||||
width, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
widthratio_node.width = width
|
||||
widthratioNode.width = width
|
||||
|
||||
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
||||
// Name follows
|
||||
name_token := arguments.MatchType(TokenIdentifier)
|
||||
if name_token == nil {
|
||||
nameToken := arguments.MatchType(TokenIdentifier)
|
||||
if nameToken == nil {
|
||||
return nil, arguments.Error("Expected name (identifier).", nil)
|
||||
}
|
||||
widthratio_node.ctx_name = name_token.Val
|
||||
widthratioNode.ctxName = nameToken.Val
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed widthratio-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return widthratio_node, nil
|
||||
return widthratioNode, nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagWithNode struct {
|
||||
with_pairs map[string]IEvaluator
|
||||
withPairs map[string]IEvaluator
|
||||
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
|
||||
withctx := NewChildExecutionContext(ctx)
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -22,12 +18,12 @@ func (node *tagWithNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *E
|
|||
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) {
|
||||
with_node := &tagWithNode{
|
||||
with_pairs: make(map[string]IEvaluator),
|
||||
withNode := &tagWithNode{
|
||||
withPairs: make(map[string]IEvaluator),
|
||||
}
|
||||
|
||||
if arguments.Count() == 0 {
|
||||
|
@ -38,7 +34,7 @@ func tagWithParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Err
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
with_node.wrapper = wrapper
|
||||
withNode.wrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
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).
|
||||
// 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++ {
|
||||
if arguments.PeekN(i, TokenKeyword, "as") != nil {
|
||||
old_style = true
|
||||
oldStyle = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for arguments.Remaining() > 0 {
|
||||
if old_style {
|
||||
value_expr, err := arguments.ParseExpression()
|
||||
if oldStyle {
|
||||
valueExpr, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if arguments.Match(TokenKeyword, "as") == nil {
|
||||
return nil, arguments.Error("Expected 'as' keyword.", nil)
|
||||
}
|
||||
key_token := arguments.MatchType(TokenIdentifier)
|
||||
if key_token == nil {
|
||||
keyToken := arguments.MatchType(TokenIdentifier)
|
||||
if keyToken == nil {
|
||||
return nil, arguments.Error("Expected an identifier", nil)
|
||||
}
|
||||
with_node.with_pairs[key_token.Val] = value_expr
|
||||
withNode.withPairs[keyToken.Val] = valueExpr
|
||||
} else {
|
||||
key_token := arguments.MatchType(TokenIdentifier)
|
||||
if key_token == nil {
|
||||
keyToken := arguments.MatchType(TokenIdentifier)
|
||||
if keyToken == nil {
|
||||
return nil, arguments.Error("Expected an identifier", nil)
|
||||
}
|
||||
if arguments.Match(TokenSymbol, "=") == nil {
|
||||
return nil, arguments.Error("Expected '='.", nil)
|
||||
}
|
||||
value_expr, err := arguments.ParseExpression()
|
||||
valueExpr, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
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() {
|
||||
|
|
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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"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 {
|
||||
set *TemplateSet
|
||||
|
||||
// Input
|
||||
is_tpl_string bool
|
||||
isTplString bool
|
||||
name string
|
||||
tpl string
|
||||
size int
|
||||
|
@ -24,30 +42,32 @@ type Template struct {
|
|||
parent *Template
|
||||
child *Template
|
||||
blocks map[string]*NodeWrapper
|
||||
exported_macros map[string]*tagMacroNode
|
||||
exportedMacros map[string]*tagMacroNode
|
||||
|
||||
// Output
|
||||
root *nodeDocument
|
||||
}
|
||||
|
||||
func newTemplateString(set *TemplateSet, tpl string) (*Template, error) {
|
||||
func newTemplateString(set *TemplateSet, tpl []byte) (*Template, error) {
|
||||
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
|
||||
t := &Template{
|
||||
set: set,
|
||||
is_tpl_string: is_tpl_string,
|
||||
isTplString: isTplString,
|
||||
name: name,
|
||||
tpl: tpl,
|
||||
size: len(tpl),
|
||||
tpl: strTpl,
|
||||
size: len(strTpl),
|
||||
blocks: make(map[string]*NodeWrapper),
|
||||
exported_macros: make(map[string]*tagMacroNode),
|
||||
exportedMacros: make(map[string]*tagMacroNode),
|
||||
}
|
||||
|
||||
// Tokenize it
|
||||
tokens, err := lex(name, tpl)
|
||||
tokens, err := lex(name, strTpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -67,11 +87,7 @@ func newTemplate(set *TemplateSet, name string, is_tpl_string bool, tpl string)
|
|||
return t, nil
|
||||
}
|
||||
|
||||
func (tpl *Template) execute(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)))
|
||||
|
||||
func (tpl *Template) execute(context Context, writer TemplateWriter) error {
|
||||
// Determine the parent to be executed (for template inheritance)
|
||||
parent := tpl
|
||||
for parent.parent != nil {
|
||||
|
@ -89,17 +105,17 @@ func (tpl *Template) execute(context Context) (*bytes.Buffer, error) {
|
|||
// Check for context name syntax
|
||||
err := newContext.checkForValidIdentifiers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for clashes with macro names
|
||||
for k, _ := range newContext {
|
||||
_, has := tpl.exported_macros[k]
|
||||
for k := range newContext {
|
||||
_, has := tpl.exportedMacros[k]
|
||||
if has {
|
||||
return nil, &Error{
|
||||
return &Error{
|
||||
Filename: tpl.name,
|
||||
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)
|
||||
|
||||
// Run the selected document
|
||||
err := parent.root.Execute(ctx, buffer)
|
||||
if err != nil {
|
||||
if err := parent.root.Execute(ctx, writer); 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 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
|
||||
// is being returned.
|
||||
func (tpl *Template) ExecuteWriter(context Context, writer io.Writer) error {
|
||||
buffer, err := tpl.execute(context)
|
||||
buf, err := tpl.newBufferAndExecute(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l := buffer.Len()
|
||||
n, werr := buffer.WriteTo(writer)
|
||||
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(),
|
||||
}
|
||||
_, err = buf.WriteTo(writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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
|
||||
func (tpl *Template) ExecuteBytes(context Context) ([]byte, error) {
|
||||
// Execute template
|
||||
buffer, err := tpl.execute(context)
|
||||
buffer, err := tpl.newBufferAndExecute(context)
|
||||
if err != nil {
|
||||
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
|
||||
func (tpl *Template) Execute(context Context) (string, error) {
|
||||
// Execute template
|
||||
buffer, err := tpl.execute(context)
|
||||
buffer, err := tpl.newBufferAndExecute(context)
|
||||
if err != nil {
|
||||
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 = ""
|
||||
}()
|
||||
}
|
||||
*/
|
252
vendor/github.com/flosch/pongo2/template_sets.go
generated
vendored
252
vendor/github.com/flosch/pongo2/template_sets.go
generated
vendored
|
@ -2,48 +2,49 @@ package pongo2
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"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
|
||||
// among all members of the set), their own configuration (like a specific base directory) and their own sandbox.
|
||||
// It's useful for a separation of different kind of templates (e. g. web templates vs. mail templates).
|
||||
// TemplateLoader allows to implement a virtual file system.
|
||||
type TemplateLoader interface {
|
||||
// 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 {
|
||||
name string
|
||||
loader TemplateLoader
|
||||
|
||||
// Globals will be provided to all templates created within this template set
|
||||
Globals Context
|
||||
|
||||
// If debug is true (default false), ExecutionContext.Logf() will work and output to STDOUT. Furthermore,
|
||||
// FromCache() won't cache the templates. Make sure to synchronize the access to it in case you're changing this
|
||||
// If debug is true (default false), ExecutionContext.Logf() will work and output
|
||||
// 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).
|
||||
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
|
||||
// - Limit access to directories (using SandboxDirectories)
|
||||
// - 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)
|
||||
// to these sandbox directories. All default pongo2 filters/tags are respecting these restrictions.
|
||||
// For example, if you only have your base directory in the list, a {% ssi "/etc/passwd" %} will not work.
|
||||
// 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
|
||||
// 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).
|
||||
firstTemplateCreated bool
|
||||
bannedTags map[string]bool
|
||||
bannedFilters map[string]bool
|
||||
|
@ -53,11 +54,13 @@ type TemplateSet struct {
|
|||
templateCacheMutex sync.Mutex
|
||||
}
|
||||
|
||||
// Create your own template sets to separate different kind of templates (e. g. web from mail templates) with
|
||||
// different globals or other configurations (like base directories).
|
||||
func NewSet(name string) *TemplateSet {
|
||||
// NewSet can be used to create sets with different kind of templates
|
||||
// (e. g. web from mail templates), with different globals or
|
||||
// other configurations.
|
||||
func NewSet(name string, loader TemplateLoader) *TemplateSet {
|
||||
return &TemplateSet{
|
||||
name: name,
|
||||
loader: loader,
|
||||
Globals: make(Context),
|
||||
bannedTags: 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
|
||||
// path in filters, tags and From*-functions to determine your template.
|
||||
func (set *TemplateSet) SetBaseDirectory(name string) error {
|
||||
// Make the path absolute
|
||||
if !filepath.IsAbs(name) {
|
||||
abs, err := filepath.Abs(name)
|
||||
if err != nil {
|
||||
return err
|
||||
func (set *TemplateSet) resolveFilename(tpl *Template, path string) string {
|
||||
name := ""
|
||||
if tpl != nil && tpl.isTplString {
|
||||
return path
|
||||
}
|
||||
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 {
|
||||
return set.baseDirectory
|
||||
}
|
||||
|
||||
// Ban a specific tag for this template set. See more in the documentation for TemplateSet.
|
||||
func (set *TemplateSet) BanTag(name string) {
|
||||
// BanTag bans a specific tag for this template set. See more in the documentation for TemplateSet.
|
||||
func (set *TemplateSet) BanTag(name string) error {
|
||||
_, has := tags[name]
|
||||
if !has {
|
||||
panic(fmt.Sprintf("Tag '%s' not found.", name))
|
||||
return errors.Errorf("tag '%s' not found", name)
|
||||
}
|
||||
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]
|
||||
if has {
|
||||
panic(fmt.Sprintf("Tag '%s' is already banned.", name))
|
||||
return errors.Errorf("tag '%s' is already banned", name)
|
||||
}
|
||||
set.bannedTags[name] = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Ban a specific filter for this template set. See more in the documentation for TemplateSet.
|
||||
func (set *TemplateSet) BanFilter(name string) {
|
||||
// BanFilter bans a specific filter for this template set. See more in the documentation for TemplateSet.
|
||||
func (set *TemplateSet) BanFilter(name string) error {
|
||||
_, has := filters[name]
|
||||
if !has {
|
||||
panic(fmt.Sprintf("Filter '%s' not found.", name))
|
||||
return errors.Errorf("filter '%s' not found", name)
|
||||
}
|
||||
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]
|
||||
if has {
|
||||
panic(fmt.Sprintf("Filter '%s' is already banned.", name))
|
||||
return errors.Errorf("filter '%s' is already banned", name)
|
||||
}
|
||||
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.
|
||||
// If TemplateSet.Debug is true (for example during development phase),
|
||||
// FromCache() will not cache the template and instead recompile it on any
|
||||
// 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) {
|
||||
if set.Debug {
|
||||
// Recompile on any request
|
||||
return set.FromFile(filename)
|
||||
} else {
|
||||
}
|
||||
// Cache the template
|
||||
cleaned_filename := set.resolveFilename(nil, filename)
|
||||
cleanedFilename := set.resolveFilename(nil, filename)
|
||||
|
||||
set.templateCacheMutex.Lock()
|
||||
defer set.templateCacheMutex.Unlock()
|
||||
|
||||
tpl, has := set.templateCache[cleaned_filename]
|
||||
tpl, has := set.templateCache[cleanedFilename]
|
||||
|
||||
// Cache miss
|
||||
if !has {
|
||||
tpl, err := set.FromFile(cleaned_filename)
|
||||
tpl, err := set.FromFile(cleanedFilename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
set.templateCache[cleaned_filename] = tpl
|
||||
set.templateCache[cleanedFilename] = tpl
|
||||
return tpl, nil
|
||||
}
|
||||
|
||||
// Cache hit
|
||||
return tpl, nil
|
||||
}
|
||||
|
||||
// FromString loads a template from string and returns a Template instance.
|
||||
func (set *TemplateSet) FromString(tpl string) (*Template, error) {
|
||||
set.firstTemplateCreated = true
|
||||
|
||||
return newTemplateString(set, []byte(tpl))
|
||||
}
|
||||
|
||||
// Loads a template from string and returns a Template instance.
|
||||
func (set *TemplateSet) FromString(tpl string) (*Template, error) {
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// FromFile loads a template from a filename and returns a Template instance.
|
||||
func (set *TemplateSet) FromFile(filename string) (*Template, error) {
|
||||
set.firstTemplateCreated = true
|
||||
|
||||
buf, err := ioutil.ReadFile(set.resolveFilename(nil, filename))
|
||||
fd, err := set.loader.Get(set.resolveFilename(nil, filename))
|
||||
if err != nil {
|
||||
return nil, &Error{
|
||||
Filename: filename,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
// Shortcut; renders a template string directly. Panics when providing a
|
||||
// malformed template or an error occurs during execution.
|
||||
func (set *TemplateSet) RenderTemplateString(s string, ctx Context) string {
|
||||
return newTemplate(set, filename, false, buf)
|
||||
}
|
||||
|
||||
// RenderTemplateString is a shortcut and renders a template string directly.
|
||||
func (set *TemplateSet) RenderTemplateString(s string, ctx Context) (string, error) {
|
||||
set.firstTemplateCreated = true
|
||||
|
||||
tpl := Must(set.FromString(s))
|
||||
result, err := tpl.Execute(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return "", err
|
||||
}
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Shortcut; renders a template file directly. Panics when providing a
|
||||
// malformed template or an error occurs during execution.
|
||||
func (set *TemplateSet) RenderTemplateFile(fn string, ctx Context) string {
|
||||
// RenderTemplateBytes is a shortcut and renders template bytes directly.
|
||||
func (set *TemplateSet) RenderTemplateBytes(b []byte, ctx Context) (string, error) {
|
||||
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
|
||||
|
||||
tpl := Must(set.FromFile(fn))
|
||||
result, err := tpl.Execute(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return "", err
|
||||
}
|
||||
return result
|
||||
return result, nil
|
||||
}
|
||||
|
||||
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)
|
||||
func logf(format string, items ...interface{}) {
|
||||
if debug {
|
||||
|
@ -279,13 +236,18 @@ func logf(format string, items ...interface{}) {
|
|||
|
||||
var (
|
||||
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
|
||||
DefaultSet = NewSet("default")
|
||||
// DefaultLoader allows the default un-sandboxed access to the local file
|
||||
// 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
|
||||
FromString = DefaultSet.FromString
|
||||
FromBytes = DefaultSet.FromBytes
|
||||
FromFile = DefaultSet.FromFile
|
||||
FromCache = DefaultSet.FromCache
|
||||
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 }}
|
||||
{{ !(5 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)
|
||||
{{ 34/3*3 }}
|
||||
{{ 10 + 24 / 6 / 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
|
||||
True
|
||||
True
|
||||
False
|
||||
True
|
||||
True
|
||||
False
|
||||
True
|
||||
False
|
||||
|
||||
issue #48 (associativity for infix operators)
|
||||
33
|
||||
12
|
||||
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) }}
|
||||
{{ simple.func_add("test", 5) }}
|
||||
{% for item in simple.multiple_item_list %} {{ simple.func_add("test", 5) }} {% endfor %}
|
||||
{{ 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
|
||||
.*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\).
|
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
|
||||
{{ simple.misc_list|join:", " }}
|
||||
|
||||
split
|
||||
{{ "Hello, 99, 3.140000, good"|split:", "|join:", " }}
|
||||
|
||||
stringformat
|
||||
{{ simple.float|stringformat:"%.2f" }}
|
||||
{{ 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
|
||||
T
|
||||
<pongo2.comment Value>
|
||||
<pongo2_test.comment Value>
|
||||
|
||||
|
||||
|
||||
|
@ -113,7 +113,7 @@ T
|
|||
|
||||
last
|
||||
t
|
||||
<pongo2.comment Value>
|
||||
<pongo2_test.comment Value>
|
||||
|
||||
|
||||
|
||||
|
@ -176,6 +176,9 @@ floatformat
|
|||
join
|
||||
Hello, 99, 3.140000, good
|
||||
|
||||
split
|
||||
Hello, 99, 3.140000, good
|
||||
|
||||
stringformat
|
||||
3.14
|
||||
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
|
||||
'{% 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
|
||||
'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 !0.0 %}!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 < 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 %}
|
||||
|
|
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
|
||||
!0.0
|
||||
!0
|
||||
false
|
||||
42
|
||||
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" 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 %}' 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 john doe' End
|
||||
Start 'I'm john doe11' 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 %}
|
||||
{% set new_var = item %}{{ new_var }}{% endfor %}
|
||||
{{ 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
|
||||
good
|
||||
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|integer }}
|
||||
{{ 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.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
|
||||
|
||||
more with tests
|
||||
<pongo2.user Value>
|
||||
<pongo2_test.user Value>
|
||||
user1
|
||||
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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -12,7 +13,7 @@ type Value struct {
|
|||
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
|
||||
// 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 {
|
||||
return &Value{
|
||||
val: reflect.ValueOf(i),
|
||||
|
@ -39,23 +40,23 @@ func (v *Value) getResolvedValue() reflect.Value {
|
|||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return v.getResolvedValue().Kind() == reflect.Float32 ||
|
||||
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 {
|
||||
return v.getResolvedValue().Kind() == reflect.Int ||
|
||||
v.getResolvedValue().Kind() == reflect.Int8 ||
|
||||
|
@ -69,19 +70,19 @@ func (v *Value) IsInteger() bool {
|
|||
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.
|
||||
func (v *Value) IsNumber() bool {
|
||||
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 {
|
||||
//fmt.Printf("%+v\n", v.getResolvedValue().Type().String())
|
||||
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
|
||||
// types for underlying values are supported:
|
||||
//
|
||||
|
@ -111,9 +112,8 @@ func (v *Value) String() string {
|
|||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
return "True"
|
||||
} else {
|
||||
return "False"
|
||||
}
|
||||
return "False"
|
||||
case reflect.Struct:
|
||||
if t, ok := v.Interface().(fmt.Stringer); ok {
|
||||
return t.String()
|
||||
|
@ -124,7 +124,7 @@ func (v *Value) String() 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,
|
||||
// it will return 0.
|
||||
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,
|
||||
// it will return 0.0.
|
||||
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
|
||||
// underlying value, have a look on the IsTrue()-function.
|
||||
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:
|
||||
//
|
||||
|
@ -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
|
||||
// return_value.IsTrue() afterwards.
|
||||
//
|
||||
|
@ -229,26 +229,26 @@ func (v *Value) Negate() *Value {
|
|||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if v.Integer() != 0 {
|
||||
return AsValue(0)
|
||||
} else {
|
||||
return AsValue(1)
|
||||
}
|
||||
return AsValue(1)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if v.Float() != 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:
|
||||
return AsValue(v.getResolvedValue().Len() == 0)
|
||||
case reflect.Bool:
|
||||
return AsValue(!v.getResolvedValue().Bool())
|
||||
case reflect.Struct:
|
||||
return AsValue(false)
|
||||
default:
|
||||
logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
|
||||
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.
|
||||
func (v *Value) Len() int {
|
||||
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.
|
||||
func (v *Value) Slice(i, j int) *Value {
|
||||
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.
|
||||
func (v *Value) Index(i int) *Value {
|
||||
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
|
||||
// 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 {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
case reflect.Struct:
|
||||
field_value := v.getResolvedValue().FieldByName(other.String())
|
||||
return field_value.IsValid()
|
||||
fieldValue := v.getResolvedValue().FieldByName(other.String())
|
||||
return fieldValue.IsValid()
|
||||
case reflect.Map:
|
||||
var map_value reflect.Value
|
||||
var mapValue reflect.Value
|
||||
switch other.Interface().(type) {
|
||||
case int:
|
||||
map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
case string:
|
||||
map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
default:
|
||||
logf("Value.Contains() does not support lookup type '%s'\n", other.getResolvedValue().Kind().String())
|
||||
return false
|
||||
}
|
||||
|
||||
return map_value.IsValid()
|
||||
return mapValue.IsValid()
|
||||
case reflect.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:
|
||||
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.
|
||||
func (v *Value) CanSlice() bool {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
|
@ -346,7 +353,7 @@ func (v *Value) CanSlice() bool {
|
|||
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:
|
||||
//
|
||||
// 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,
|
||||
// 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()) {
|
||||
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.
|
||||
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() {
|
||||
case reflect.Map:
|
||||
// Reverse not needed for maps, since they are not ordered
|
||||
keys := v.getResolvedValue().MapKeys()
|
||||
keys := sortedKeys(v.getResolvedValue().MapKeys())
|
||||
if sorted {
|
||||
if reverse {
|
||||
sort.Sort(sort.Reverse(keys))
|
||||
} else {
|
||||
sort.Sort(keys)
|
||||
}
|
||||
}
|
||||
keyLen := len(keys)
|
||||
for idx, key := range keys {
|
||||
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
|
||||
case reflect.Array, reflect.Slice:
|
||||
var items valuesList
|
||||
|
||||
itemCount := v.getResolvedValue().Len()
|
||||
if itemCount > 0 {
|
||||
if reverse {
|
||||
for i := itemCount - 1; i >= 0; i-- {
|
||||
if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
|
||||
return
|
||||
for i := 0; i < itemCount; i++ {
|
||||
items = append(items, &Value{val: v.getResolvedValue().Index(i)})
|
||||
}
|
||||
|
||||
if sorted {
|
||||
if reverse {
|
||||
sort.Sort(sort.Reverse(items))
|
||||
} else {
|
||||
sort.Sort(items)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < itemCount; i++ {
|
||||
if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
|
||||
return
|
||||
if reverse {
|
||||
for i := 0; i < itemCount/2; i++ {
|
||||
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 {
|
||||
empty()
|
||||
}
|
||||
return // done
|
||||
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()
|
||||
if charCount > 0 {
|
||||
if reverse {
|
||||
|
@ -425,7 +456,7 @@ func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, em
|
|||
empty()
|
||||
}
|
||||
|
||||
// Gives you access to the underlying value.
|
||||
// Interface gives you access to the underlying value.
|
||||
func (v *Value) Interface() interface{} {
|
||||
if v.val.IsValid() {
|
||||
return v.val.Interface()
|
||||
|
@ -433,7 +464,57 @@ func (v *Value) Interface() interface{} {
|
|||
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 {
|
||||
// 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()
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -13,13 +14,18 @@ const (
|
|||
varTypeIdent
|
||||
)
|
||||
|
||||
var (
|
||||
typeOfValuePtr = reflect.TypeOf(new(Value))
|
||||
typeOfExecCtxPtr = reflect.TypeOf(new(ExecutionContext))
|
||||
)
|
||||
|
||||
type variablePart struct {
|
||||
typ int
|
||||
s string
|
||||
i int
|
||||
|
||||
is_function_call bool
|
||||
calling_args []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
|
||||
isFunctionCall bool
|
||||
callingArgs []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
|
||||
}
|
||||
|
||||
type functionCallArgument interface {
|
||||
|
@ -28,119 +34,121 @@ type functionCallArgument interface {
|
|||
|
||||
// TODO: Add location tokens
|
||||
type stringResolver struct {
|
||||
location_token *Token
|
||||
locationToken *Token
|
||||
val string
|
||||
}
|
||||
|
||||
type intResolver struct {
|
||||
location_token *Token
|
||||
locationToken *Token
|
||||
val int
|
||||
}
|
||||
|
||||
type floatResolver struct {
|
||||
location_token *Token
|
||||
locationToken *Token
|
||||
val float64
|
||||
}
|
||||
|
||||
type boolResolver struct {
|
||||
location_token *Token
|
||||
locationToken *Token
|
||||
val bool
|
||||
}
|
||||
|
||||
type variableResolver struct {
|
||||
location_token *Token
|
||||
locationToken *Token
|
||||
|
||||
parts []*variablePart
|
||||
}
|
||||
|
||||
type nodeFilteredVariable struct {
|
||||
location_token *Token
|
||||
locationToken *Token
|
||||
|
||||
resolver IEvaluator
|
||||
filterChain []*filterCall
|
||||
}
|
||||
|
||||
type nodeVariable struct {
|
||||
location_token *Token
|
||||
locationToken *Token
|
||||
expr IEvaluator
|
||||
}
|
||||
|
||||
func (expr *nodeFilteredVariable) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
value, err := expr.Evaluate(ctx)
|
||||
type executionCtxEval struct{}
|
||||
|
||||
func (v *nodeFilteredVariable) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
value, err := v.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expr *variableResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
value, err := expr.Evaluate(ctx)
|
||||
func (vr *variableResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
value, err := vr.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expr *stringResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
value, err := expr.Evaluate(ctx)
|
||||
func (s *stringResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
value, err := s.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expr *intResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
value, err := expr.Evaluate(ctx)
|
||||
func (i *intResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
value, err := i.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expr *floatResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
value, err := expr.Evaluate(ctx)
|
||||
func (f *floatResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
value, err := f.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (expr *boolResolver) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
value, err := expr.Evaluate(ctx)
|
||||
func (b *boolResolver) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
value, err := b.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buffer.WriteString(value.String())
|
||||
writer.WriteString(value.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *nodeFilteredVariable) GetPositionToken() *Token {
|
||||
return v.location_token
|
||||
return v.locationToken
|
||||
}
|
||||
|
||||
func (v *variableResolver) GetPositionToken() *Token {
|
||||
return v.location_token
|
||||
func (vr *variableResolver) GetPositionToken() *Token {
|
||||
return vr.locationToken
|
||||
}
|
||||
|
||||
func (v *stringResolver) GetPositionToken() *Token {
|
||||
return v.location_token
|
||||
func (s *stringResolver) GetPositionToken() *Token {
|
||||
return s.locationToken
|
||||
}
|
||||
|
||||
func (v *intResolver) GetPositionToken() *Token {
|
||||
return v.location_token
|
||||
func (i *intResolver) GetPositionToken() *Token {
|
||||
return i.locationToken
|
||||
}
|
||||
|
||||
func (v *floatResolver) GetPositionToken() *Token {
|
||||
return v.location_token
|
||||
func (f *floatResolver) GetPositionToken() *Token {
|
||||
return f.locationToken
|
||||
}
|
||||
|
||||
func (v *boolResolver) GetPositionToken() *Token {
|
||||
return v.location_token
|
||||
func (b *boolResolver) GetPositionToken() *Token {
|
||||
return b.locationToken
|
||||
}
|
||||
|
||||
func (s *stringResolver) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||
|
@ -179,7 +187,7 @@ func (nv *nodeVariable) FilterApplied(name string) bool {
|
|||
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)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (executionCtxEval) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
|
||||
return AsValue(ctx), nil
|
||||
}
|
||||
|
||||
func (vr *variableResolver) FilterApplied(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
@ -218,15 +230,15 @@ func (vr *variableResolver) String() string {
|
|||
|
||||
func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
||||
var current reflect.Value
|
||||
var is_safe bool
|
||||
var isSafe bool
|
||||
|
||||
for idx, part := range vr.parts {
|
||||
if idx == 0 {
|
||||
// We're looking up the first part of the variable.
|
||||
// First we're having a look in our private
|
||||
// context (e. g. information provided by tags, like the forloop)
|
||||
val, in_private := ctx.Private[vr.parts[0].s]
|
||||
if !in_private {
|
||||
val, inPrivate := ctx.Private[vr.parts[0].s]
|
||||
if !inPrivate {
|
||||
// Nothing found? Then have a final lookup in the public context
|
||||
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
|
||||
// Problem with resolving the pointer is we're changing the receiver
|
||||
is_func := false
|
||||
isFunc := false
|
||||
if part.typ == varTypeIdent {
|
||||
func_value := current.MethodByName(part.s)
|
||||
if func_value.IsValid() {
|
||||
current = func_value
|
||||
is_func = true
|
||||
funcValue := current.MethodByName(part.s)
|
||||
if funcValue.IsValid() {
|
||||
current = funcValue
|
||||
isFunc = true
|
||||
}
|
||||
}
|
||||
|
||||
if !is_func {
|
||||
if !isFunc {
|
||||
// If current a pointer, resolve it
|
||||
if current.Kind() == reflect.Ptr {
|
||||
current = current.Elem()
|
||||
|
@ -262,9 +274,14 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
|||
// * slices/arrays/strings
|
||||
switch current.Kind() {
|
||||
case reflect.String, reflect.Array, reflect.Slice:
|
||||
if part.i >= 0 && current.Len() > part.i {
|
||||
current = current.Index(part.i)
|
||||
} else {
|
||||
// In Django, exceeding the length of a list is just empty.
|
||||
return AsValue(nil), nil
|
||||
}
|
||||
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())
|
||||
}
|
||||
case varTypeIdent:
|
||||
|
@ -278,7 +295,7 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
|||
case reflect.Map:
|
||||
current = current.MapIndex(reflect.ValueOf(part.s))
|
||||
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())
|
||||
}
|
||||
default:
|
||||
|
@ -295,10 +312,10 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
|
|||
// If current is a reflect.ValueOf(pongo2.Value), then unpack it
|
||||
// Happens in function calls (as a return value) or by injecting
|
||||
// into the execution context (e.g. in a for-loop)
|
||||
if current.Type() == reflect.TypeOf(&Value{}) {
|
||||
tmp_value := current.Interface().(*Value)
|
||||
current = tmp_value.val
|
||||
is_safe = tmp_value.safe
|
||||
if current.Type() == typeOfValuePtr {
|
||||
tmpValue := current.Interface().(*Value)
|
||||
current = tmpValue.val
|
||||
isSafe = tmpValue.safe
|
||||
}
|
||||
|
||||
// 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
|
||||
if part.is_function_call || current.Kind() == reflect.Func {
|
||||
if part.isFunctionCall || current.Kind() == reflect.Func {
|
||||
// Check for callable
|
||||
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
|
||||
// func(*Value, ...) *Value
|
||||
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
|
||||
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,
|
||||
fmt.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))
|
||||
errors.Errorf("Function input argument count (%d) of '%s' must be equal to the calling argument count (%d).",
|
||||
t.NumIn(), vr.String(), len(currArgs))
|
||||
}
|
||||
|
||||
// Output arguments
|
||||
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
|
||||
parameters := make([]reflect.Value, 0)
|
||||
var parameters []reflect.Value
|
||||
|
||||
num_args := t.NumIn()
|
||||
is_variadic := t.IsVariadic()
|
||||
var fn_arg reflect.Type
|
||||
numArgs := t.NumIn()
|
||||
isVariadic := t.IsVariadic()
|
||||
var fnArg reflect.Type
|
||||
|
||||
for idx, arg := range part.calling_args {
|
||||
for idx, arg := range currArgs {
|
||||
pv, err := arg.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if is_variadic {
|
||||
if isVariadic {
|
||||
if idx >= t.NumIn()-1 {
|
||||
fn_arg = t.In(num_args - 1).Elem()
|
||||
fnArg = t.In(numArgs - 1).Elem()
|
||||
} else {
|
||||
fn_arg = t.In(idx)
|
||||
fnArg = t.In(idx)
|
||||
}
|
||||
} 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
|
||||
if !is_variadic {
|
||||
if fn_arg != reflect.TypeOf(pv.Interface()) && fn_arg.Kind() != reflect.Interface {
|
||||
return nil, fmt.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())
|
||||
} else {
|
||||
if !isVariadic {
|
||||
if fnArg != reflect.TypeOf(pv.Interface()) && fnArg.Kind() != reflect.Interface {
|
||||
return nil, errors.Errorf("Function input argument %d of '%s' must be of type %s or *pongo2.Value (not %T).",
|
||||
idx, vr.String(), fnArg.String(), pv.Interface())
|
||||
}
|
||||
// Function's argument has another type, using the interface-value
|
||||
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
|
||||
parameters = append(parameters, reflect.ValueOf(pv.Interface()))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Function's argument is a *pongo2.Value
|
||||
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
|
||||
rv := current.Call(parameters)[0]
|
||||
|
||||
if rv.Type() != reflect.TypeOf(new(Value)) {
|
||||
if rv.Type() != typeOfValuePtr {
|
||||
current = reflect.ValueOf(rv.Interface())
|
||||
} else {
|
||||
// Return the function call value
|
||||
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)
|
||||
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) {
|
||||
value, err := vr.resolve(ctx)
|
||||
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
|
||||
}
|
||||
|
@ -436,7 +464,7 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
|||
t := p.Current()
|
||||
|
||||
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)
|
||||
|
@ -460,25 +488,25 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
|||
return nil, p.Error(err.Error(), t)
|
||||
}
|
||||
fr := &floatResolver{
|
||||
location_token: t,
|
||||
locationToken: t,
|
||||
val: f,
|
||||
}
|
||||
return fr, nil
|
||||
} else {
|
||||
}
|
||||
i, err := strconv.Atoi(t.Val)
|
||||
if err != nil {
|
||||
return nil, p.Error(err.Error(), t)
|
||||
}
|
||||
nr := &intResolver{
|
||||
location_token: t,
|
||||
locationToken: t,
|
||||
val: i,
|
||||
}
|
||||
return nr, nil
|
||||
}
|
||||
|
||||
case TokenString:
|
||||
p.Consume()
|
||||
sr := &stringResolver{
|
||||
location_token: t,
|
||||
locationToken: t,
|
||||
val: t.Val,
|
||||
}
|
||||
return sr, nil
|
||||
|
@ -487,13 +515,13 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
|||
switch t.Val {
|
||||
case "true":
|
||||
br := &boolResolver{
|
||||
location_token: t,
|
||||
locationToken: t,
|
||||
val: true,
|
||||
}
|
||||
return br, nil
|
||||
case "false":
|
||||
br := &boolResolver{
|
||||
location_token: t,
|
||||
locationToken: t,
|
||||
val: false,
|
||||
}
|
||||
return br, nil
|
||||
|
@ -503,7 +531,7 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
|
|||
}
|
||||
|
||||
resolver := &variableResolver{
|
||||
location_token: t,
|
||||
locationToken: t,
|
||||
}
|
||||
|
||||
// First part of a variable MUST be an identifier
|
||||
|
@ -551,26 +579,26 @@ variableLoop:
|
|||
} else {
|
||||
// EOF
|
||||
return nil, p.Error("Unexpected EOF, expected either IDENTIFIER or NUMBER after DOT.",
|
||||
p.last_token)
|
||||
p.lastToken)
|
||||
}
|
||||
} else if p.Match(TokenSymbol, "(") != nil {
|
||||
// Function call
|
||||
// FunctionName '(' Comma-separated list of expressions ')'
|
||||
part := resolver.parts[len(resolver.parts)-1]
|
||||
part.is_function_call = true
|
||||
part.isFunctionCall = true
|
||||
argumentLoop:
|
||||
for {
|
||||
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 {
|
||||
// No closing bracket, so we're parsing an expression
|
||||
expr_arg, err := p.ParseExpression()
|
||||
exprArg, err := p.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part.calling_args = append(part.calling_args, expr_arg)
|
||||
part.callingArgs = append(part.callingArgs, exprArg)
|
||||
|
||||
if p.Match(TokenSymbol, ")") != nil {
|
||||
// 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) {
|
||||
v := &nodeFilteredVariable{
|
||||
location_token: p.Current(),
|
||||
locationToken: p.Current(),
|
||||
}
|
||||
|
||||
// Parse the variable name
|
||||
|
@ -621,15 +649,13 @@ filterLoop:
|
|||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
v.filterChain = append(v.filterChain, filter)
|
||||
|
||||
continue filterLoop
|
||||
|
||||
return nil, p.Error("This token is not allowed within a variable.", nil)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
|
@ -637,7 +663,7 @@ filterLoop:
|
|||
|
||||
func (p *Parser) parseVariableElement() (INode, *Error) {
|
||||
node := &nodeVariable{
|
||||
location_token: p.Current(),
|
||||
locationToken: p.Current(),
|
||||
}
|
||||
|
||||
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