diff --git a/.gitignore b/.gitignore
index 79b007c..90c97b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
certcheck
+promcertcheck
diff --git a/Gopkg.lock b/Gopkg.lock
index d24da23..a0357ad 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -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
diff --git a/Gopkg.toml b/Gopkg.toml
index d4dd19b..62974f7 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -27,6 +27,7 @@
[[constraint]]
name = "github.com/flosch/pongo2"
+ branch = "master"
[[constraint]]
name = "github.com/gorilla/mux"
diff --git a/promcertcheck b/promcertcheck
deleted file mode 100755
index 5f64e3e..0000000
Binary files a/promcertcheck and /dev/null differ
diff --git a/vendor/github.com/flosch/pongo2/.gitignore b/vendor/github.com/flosch/pongo2/.gitignore
index 37eaf44..1346be5 100644
--- a/vendor/github.com/flosch/pongo2/.gitignore
+++ b/vendor/github.com/flosch/pongo2/.gitignore
@@ -7,6 +7,7 @@
_obj
_test
.idea
+.vscode
# Architecture specific extensions/prefixes
*.[568vq]
diff --git a/vendor/github.com/flosch/pongo2/.travis.yml b/vendor/github.com/flosch/pongo2/.travis.yml
index a22ad21..0445a45 100644
--- a/vendor/github.com/flosch/pongo2/.travis.yml
+++ b/vendor/github.com/flosch/pongo2/.travis.yml
@@ -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'
diff --git a/vendor/github.com/flosch/pongo2/README.md b/vendor/github.com/flosch/pongo2/README.md
index 7c61e9e..33def30 100644
--- a/vendor/github.com/flosch/pongo2/README.md
+++ b/vendor/github.com/flosch/pongo2/README.md
@@ -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. :-)
@@ -115,7 +117,8 @@ For a documentation on how the templating language works you can [head over to t
You can access pongo2's API documentation on [godoc](https://godoc.org/github.com/flosch/pongo2).
## 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,8 +157,12 @@ 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.
# API-usage examples
diff --git a/vendor/github.com/flosch/pongo2/context.go b/vendor/github.com/flosch/pongo2/context.go
index df587c8..6e3c166 100644
--- a/vendor/github.com/flosch/pongo2/context.go
+++ b/vendor/github.com/flosch/pongo2/context.go
@@ -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:
@@ -24,14 +25,15 @@ func (c Context) checkForValidIdentifiers() *Error {
for k, v := range c {
if !reIdentifiers.MatchString(k) {
return &Error{
- Sender: "checkForValidIdentifiers",
- ErrorMsg: fmt.Sprintf("Context-key '%s' (value: '%+v') is not a valid identifier.", k, v),
+ Sender: "checkForValidIdentifiers",
+ 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 {
@@ -107,13 +115,13 @@ func (ctx *ExecutionContext) Error(msg string, token *Token) *Error {
col = token.Col
}
return &Error{
- Template: ctx.template,
- Filename: filename,
- Line: line,
- Column: col,
- Token: token,
- Sender: "execution",
- ErrorMsg: msg,
+ Template: ctx.template,
+ Filename: filename,
+ Line: line,
+ Column: col,
+ Token: token,
+ Sender: "execution",
+ OrigError: err,
}
}
diff --git a/vendor/github.com/flosch/pongo2/error.go b/vendor/github.com/flosch/pongo2/error.go
index c1ee86e..8aec8c1 100644
--- a/vendor/github.com/flosch/pongo2/error.go
+++ b/vendor/github.com/flosch/pongo2/error.go
@@ -6,20 +6,20 @@ 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
// a filter, make Sender equals 'filter:yourfilter'; same goes for tags: 'tag:mytag').
// It's okay if you only fill in ErrorMsg if you don't have any other details at hand.
type Error struct {
- Template *Template
- Filename string
- Line int
- Column int
- Token *Token
- Sender string
- ErrorMsg string
+ Template *Template
+ Filename string
+ Line int
+ Column int
+ Token *Token
+ Sender 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 == "" {
- 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
}
diff --git a/vendor/github.com/flosch/pongo2/filters.go b/vendor/github.com/flosch/pongo2/filters.go
index 229f7fe..1092705 100644
--- a/vendor/github.com/flosch/pongo2/filters.go
+++ b/vendor/github.com/flosch/pongo2/filters.go
@@ -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),
+ Sender: "applyfilter",
+ 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
diff --git a/vendor/github.com/flosch/pongo2/filters_builtin.go b/vendor/github.com/flosch/pongo2/filters_builtin.go
index aaa68b1..f02b491 100644
--- a/vendor/github.com/flosch/pongo2/filters_builtin.go
+++ b/vendor/github.com/flosch/pongo2/filters_builtin.go
@@ -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
}
+ 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'.",
+ Sender: "filter:date",
+ 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", "
", -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%s%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(`%s`, 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
}
@@ -746,8 +771,8 @@ func filterPluralize(in *Value, param *Value) (*Value, *Error) {
endings := strings.Split(param.String(), ",")
if len(endings) > 2 {
return nil, &Error{
- Sender: "filter:pluralize",
- ErrorMsg: "You cannot pass more than 2 arguments to filter 'pluralize'.",
+ Sender: "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.",
- }
+ }
+ return nil, &Error{
+ Sender: "filter:pluralize",
+ OrigError: errors.New("filter 'pluralize' does only work on numbers"),
}
}
@@ -807,8 +831,8 @@ func filterSlice(in *Value, param *Value) (*Value, *Error) {
comp := strings.Split(param.String(), ":")
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]",
+ Sender: "filter:slice",
+ 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),
+ Sender: "filter:yesno",
+ 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),
+ Sender: "filter:yesno",
+ 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]
}
}
diff --git a/vendor/github.com/flosch/pongo2/lexer.go b/vendor/github.com/flosch/pongo2/lexer.go
index 8956f9c..36280de 100644
--- a/vendor/github.com/flosch/pongo2/lexer.go
+++ b/vendor/github.com/flosch/pongo2/lexer.go
@@ -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 {
@@ -111,11 +113,11 @@ func lex(name string, input string) ([]*Token, *Error) {
if l.errored {
errtoken := l.tokens[len(l.tokens)-1]
return nil, &Error{
- Filename: name,
- Line: errtoken.Line,
- Column: errtoken.Col,
- Sender: "lexer",
- ErrorMsg: errtoken.Val,
+ Filename: name,
+ Line: errtoken.Line,
+ Column: errtoken.Col,
+ Sender: "lexer",
+ 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
diff --git a/vendor/github.com/flosch/pongo2/nodes.go b/vendor/github.com/flosch/pongo2/nodes.go
index 5fd5a6c..5b039cd 100644
--- a/vendor/github.com/flosch/pongo2/nodes.go
+++ b/vendor/github.com/flosch/pongo2/nodes.go
@@ -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
}
diff --git a/vendor/github.com/flosch/pongo2/nodes_html.go b/vendor/github.com/flosch/pongo2/nodes_html.go
index 9aa630c..9680285 100644
--- a/vendor/github.com/flosch/pongo2/nodes_html.go
+++ b/vendor/github.com/flosch/pongo2/nodes_html.go
@@ -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
}
diff --git a/vendor/github.com/flosch/pongo2/nodes_wrapper.go b/vendor/github.com/flosch/pongo2/nodes_wrapper.go
index 9180dc7..d1bcb8d 100644
--- a/vendor/github.com/flosch/pongo2/nodes_wrapper.go
+++ b/vendor/github.com/flosch/pongo2/nodes_wrapper.go
@@ -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
}
diff --git a/vendor/github.com/flosch/pongo2/parser.go b/vendor/github.com/flosch/pongo2/parser.go
index c85e2d2..d0e08b5 100644
--- a/vendor/github.com/flosch/pongo2/parser.go
+++ b/vendor/github.com/flosch/pongo2/parser.go
@@ -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 {
@@ -27,10 +28,10 @@ type IEvaluator interface {
//
// (See Token's documentation for more about tokens)
type Parser struct {
- name string
- idx int
- tokens []*Token
- last_token *Token
+ name string
+ idx int
+ tokens []*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.
@@ -196,13 +197,13 @@ func (p *Parser) Error(msg string, token *Token) *Error {
col = token.Col
}
return &Error{
- Template: p.template,
- Filename: p.name,
- Sender: "parser",
- Line: line,
- Column: col,
- Token: token,
- ErrorMsg: msg,
+ Template: p.template,
+ Filename: p.name,
+ Sender: "parser",
+ Line: line,
+ Column: col,
+ Token: token,
+ 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,16 +239,15 @@ 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)
- }
- tagArgs = append(tagArgs, t)
}
+ t := p.Current()
+ p.Consume()
+ if t == nil {
+ 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)
}
diff --git a/vendor/github.com/flosch/pongo2/parser_expression.go b/vendor/github.com/flosch/pongo2/parser_expression.go
index c1002de..988468e 100644
--- a/vendor/github.com/flosch/pongo2/parser_expression.go
+++ b/vendor/github.com/flosch/pongo2/parser_expression.go
@@ -1,38 +1,37 @@
package pongo2
import (
- "bytes"
"fmt"
"math"
)
type Expression struct {
// TODO: Add location token?
- expr1 IEvaluator
- expr2 IEvaluator
- op_token *Token
+ expr1 IEvaluator
+ expr2 IEvaluator
+ opToken *Token
}
type relationalExpression struct {
// TODO: Add location token?
- expr1 IEvaluator
- expr2 IEvaluator
- op_token *Token
+ expr1 IEvaluator
+ expr2 IEvaluator
+ opToken *Token
}
type simpleExpression struct {
- negate bool
- negative_sign bool
- term1 IEvaluator
- term2 IEvaluator
- op_token *Token
+ negate bool
+ negativeSign bool
+ term1 IEvaluator
+ term2 IEvaluator
+ opToken *Token
}
type term struct {
// TODO: Add location token?
- factor1 IEvaluator
- factor2 IEvaluator
- op_token *Token
+ factor1 IEvaluator
+ factor2 IEvaluator
+ 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
}
+ // 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
}
+ // 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 {
diff --git a/vendor/github.com/flosch/pongo2/pongo2.go b/vendor/github.com/flosch/pongo2/pongo2.go
index e61faa4..eda3aa0 100644
--- a/vendor/github.com/flosch/pongo2/pongo2.go
+++ b/vendor/github.com/flosch/pongo2/pongo2.go
@@ -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 {
diff --git a/vendor/github.com/flosch/pongo2/pongo2_issues_test.go b/vendor/github.com/flosch/pongo2/pongo2_issues_test.go
index 731a290..725ab41 100644
--- a/vendor/github.com/flosch/pongo2/pongo2_issues_test.go
+++ b/vendor/github.com/flosch/pongo2/pongo2_issues_test.go
@@ -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 TestIssue151(t *testing.T) {
+ tpl, err := pongo2.FromString("{{ mydict.51232_3 }}{{ 12345_123}}{{ 995189baz }}")
+ if err != nil {
+ t.Fatal(err)
+ }
-func TestIssues(t *testing.T) { TestingT(t) }
+ str, err := tpl.Execute(pongo2.Context{
+ "mydict": map[string]string{
+ "51232_3": "foo",
+ },
+ "12345_123": "bar",
+ "995189baz": "baz",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
-type IssueTestSuite struct{}
-
-var _ = Suite(&IssueTestSuite{})
-
-func (s *TestSuite) TestIssues(c *C) {
- // Add a test for any issue
- c.Check(42, Equals, 42)
+ if str != "foobarbaz" {
+ t.Fatalf("Expected output 'foobarbaz', but got '%s'.", str)
+ }
}
diff --git a/vendor/github.com/flosch/pongo2/pongo2_template_test.go b/vendor/github.com/flosch/pongo2/pongo2_template_test.go
index b6dc8fa..4b7d8fa 100644
--- a/vendor/github.com/flosch/pongo2/pongo2_template_test.go
+++ b/vendor/github.com/flosch/pongo2/pongo2_template_test.go
@@ -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,74 +62,53 @@ 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",
- "nil": nil,
- "uint": uint(8),
- "float": float64(3.1415),
- "str": "string",
+ "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),
+ "str": "string",
"chinese_hello_world": "你好世界",
"bool_true": true,
"bool_false": false,
@@ -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": "",
"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: "Hello!
Welcome to my new blog page. I'm using pongo2 which supports {{ variables }} and {% tags %}.
",
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)
}
diff --git a/vendor/github.com/flosch/pongo2/pongo2_test.go b/vendor/github.com/flosch/pongo2/pongo2_test.go
index 5f54584..3a4f6b7 100644
--- a/vendor/github.com/flosch/pongo2/pongo2_test.go
+++ b/vendor/github.com/flosch/pongo2/pongo2_test.go
@@ -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")
+ _ = Suite(&TestSuite{})
+ 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)
+}
diff --git a/vendor/github.com/flosch/pongo2/tags.go b/vendor/github.com/flosch/pongo2/tags.go
index 292c30d..3668b06 100644
--- a/vendor/github.com/flosch/pongo2/tags.go
+++ b/vendor/github.com/flosch/pongo2/tags.go
@@ -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)
}
diff --git a/vendor/github.com/flosch/pongo2/tags_autoescape.go b/vendor/github.com/flosch/pongo2/tags_autoescape.go
index ec30438..590a1db 100644
--- a/vendor/github.com/flosch/pongo2/tags_autoescape.go
+++ b/vendor/github.com/flosch/pongo2/tags_autoescape.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_block.go b/vendor/github.com/flosch/pongo2/tags_block.go
index 30e205a..86145f3 100644
--- a/vendor/github.com/flosch/pongo2/tags_block.go
+++ b/vendor/github.com/flosch/pongo2/tags_block.go
@@ -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)
+ }
+ tpl = tpl.child
}
- return t
+
+ return nodeWrappers
}
-func (node *tagBlockNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
+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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_comment.go b/vendor/github.com/flosch/pongo2/tags_comment.go
index 8c22496..56a02ed 100644
--- a/vendor/github.com/flosch/pongo2/tags_comment.go
+++ b/vendor/github.com/flosch/pongo2/tags_comment.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_cycle.go b/vendor/github.com/flosch/pongo2/tags_cycle.go
index 6a6830e..ffbd254 100644
--- a/vendor/github.com/flosch/pongo2/tags_cycle.go
+++ b/vendor/github.com/flosch/pongo2/tags_cycle.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_extends.go b/vendor/github.com/flosch/pongo2/tags_extends.go
index 6abbb6b..5771020 100644
--- a/vendor/github.com/flosch/pongo2/tags_extends.go
+++ b/vendor/github.com/flosch/pongo2/tags_extends.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_filter.go b/vendor/github.com/flosch/pongo2/tags_filter.go
index f421e5a..b38fd92 100644
--- a/vendor/github.com/flosch/pongo2/tags_filter.go
+++ b/vendor/github.com/flosch/pongo2/tags_filter.go
@@ -5,8 +5,8 @@ import (
)
type nodeFilterCall struct {
- name string
- param_expr IEvaluator
+ name string
+ 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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_firstof.go b/vendor/github.com/flosch/pongo2/tags_firstof.go
index b677979..5b2888e 100644
--- a/vendor/github.com/flosch/pongo2/tags_firstof.go
+++ b/vendor/github.com/flosch/pongo2/tags_firstof.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_for.go b/vendor/github.com/flosch/pongo2/tags_for.go
index de56699..5b0b555 100644
--- a/vendor/github.com/flosch/pongo2/tags_for.go
+++ b/vendor/github.com/flosch/pongo2/tags_for.go
@@ -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
- reversed bool
+ key string
+ value string // only for maps: for key, value in map
+ 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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_if.go b/vendor/github.com/flosch/pongo2/tags_if.go
index 2515c44..3eeaf3b 100644
--- a/vendor/github.com/flosch/pongo2/tags_if.go
+++ b/vendor/github.com/flosch/pongo2/tags_if.go
@@ -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 {
- // 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].Execute(ctx, writer)
+ }
+ // Last condition?
+ if len(node.conditions) == i+1 && len(node.wrappers) > i+1 {
+ 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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_ifchanged.go b/vendor/github.com/flosch/pongo2/tags_ifchanged.go
index 4412ace..45296a0 100644
--- a/vendor/github.com/flosch/pongo2/tags_ifchanged.go
+++ b/vendor/github.com/flosch/pongo2/tags_ifchanged.go
@@ -5,16 +5,15 @@ import (
)
type tagIfchangedNode struct {
- watched_expr []IEvaluator
- last_values []*Value
- last_content []byte
- thenWrapper *NodeWrapper
- elseWrapper *NodeWrapper
+ 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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_ifequal.go b/vendor/github.com/flosch/pongo2/tags_ifequal.go
index 035b8fd..103f1c7 100644
--- a/vendor/github.com/flosch/pongo2/tags_ifequal.go
+++ b/vendor/github.com/flosch/pongo2/tags_ifequal.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_ifnotequal.go b/vendor/github.com/flosch/pongo2/tags_ifnotequal.go
index 1c1ba53..0d287d3 100644
--- a/vendor/github.com/flosch/pongo2/tags_ifnotequal.go
+++ b/vendor/github.com/flosch/pongo2/tags_ifnotequal.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_import.go b/vendor/github.com/flosch/pongo2/tags_import.go
index 2abeccd..7e0d6a0 100644
--- a/vendor/github.com/flosch/pongo2/tags_import.go
+++ b/vendor/github.com/flosch/pongo2/tags_import.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_include.go b/vendor/github.com/flosch/pongo2/tags_include.go
index 7a7cce2..6d619fd 100644
--- a/vendor/github.com/flosch/pongo2/tags_include.go
+++ b/vendor/github.com/flosch/pongo2/tags_include.go
@@ -1,41 +1,38 @@
package pongo2
-import (
- "bytes"
-)
-
type tagIncludeNode struct {
- tpl *Template
- filename_evaluator IEvaluator
- lazy bool
- only bool
- filename string
- with_pairs map[string]IEvaluator
+ tpl *Template
+ filenameEvaluator IEvaluator
+ lazy bool
+ only bool
+ filename string
+ 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)
- if err != nil {
- return err.(*Error)
- }
- return nil
}
+ // Template is already parsed with static filename
+ 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
+ }
+ return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, filenameToken)
}
- include_node.tpl = included_tpl
+ 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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_lorem.go b/vendor/github.com/flosch/pongo2/tags_lorem.go
index 16b018c..1d353f2 100644
--- a/vendor/github.com/flosch/pongo2/tags_lorem.go
+++ b/vendor/github.com/flosch/pongo2/tags_lorem.go
@@ -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("")
+ writer.WriteString("
")
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
- buffer.WriteString(par)
- buffer.WriteString("
")
+ writer.WriteString(par)
+ writer.WriteString("
")
}
} else {
for i := 0; i < node.count; i++ {
if i > 0 {
- buffer.WriteString("\n")
+ writer.WriteString("\n")
}
- buffer.WriteString("")
+ writer.WriteString("
")
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
- buffer.WriteString(par)
- buffer.WriteString("
")
+ writer.WriteString(par)
+ writer.WriteString("")
}
}
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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_macro.go b/vendor/github.com/flosch/pongo2/tags_macro.go
index 41cba99..dd3e0bf 100644
--- a/vendor/github.com/flosch/pongo2/tags_macro.go
+++ b/vendor/github.com/flosch/pongo2/tags_macro.go
@@ -6,16 +6,16 @@ import (
)
type tagMacroNode struct {
- position *Token
- name string
- args_order []string
- args map[string]IEvaluator
- exported bool
+ position *Token
+ name 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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_now.go b/vendor/github.com/flosch/pongo2/tags_now.go
index 0f4320f..d9fa4a3 100644
--- a/vendor/github.com/flosch/pongo2/tags_now.go
+++ b/vendor/github.com/flosch/pongo2/tags_now.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_set.go b/vendor/github.com/flosch/pongo2/tags_set.go
index 2729f44..be121c1 100644
--- a/vendor/github.com/flosch/pongo2/tags_set.go
+++ b/vendor/github.com/flosch/pongo2/tags_set.go
@@ -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 {
diff --git a/vendor/github.com/flosch/pongo2/tags_spaceless.go b/vendor/github.com/flosch/pongo2/tags_spaceless.go
index a4b3003..4fa851b 100644
--- a/vendor/github.com/flosch/pongo2/tags_spaceless.go
+++ b/vendor/github.com/flosch/pongo2/tags_spaceless.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_ssi.go b/vendor/github.com/flosch/pongo2/tags_ssi.go
index 3c3894f..c33858d 100644
--- a/vendor/github.com/flosch/pongo2/tags_ssi.go
+++ b/vendor/github.com/flosch/pongo2/tags_ssi.go
@@ -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)
+ Sender: "tag:ssi",
+ 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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_templatetag.go b/vendor/github.com/flosch/pongo2/tags_templatetag.go
index ffd3d9d..164b4dc 100644
--- a/vendor/github.com/flosch/pongo2/tags_templatetag.go
+++ b/vendor/github.com/flosch/pongo2/tags_templatetag.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_widthratio.go b/vendor/github.com/flosch/pongo2/tags_widthratio.go
index d7d7141..70c9c3e 100644
--- a/vendor/github.com/flosch/pongo2/tags_widthratio.go
+++ b/vendor/github.com/flosch/pongo2/tags_widthratio.go
@@ -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() {
diff --git a/vendor/github.com/flosch/pongo2/tags_with.go b/vendor/github.com/flosch/pongo2/tags_with.go
index 5bf4af0..32b3c1c 100644
--- a/vendor/github.com/flosch/pongo2/tags_with.go
+++ b/vendor/github.com/flosch/pongo2/tags_with.go
@@ -1,20 +1,16 @@
package pongo2
-import (
- "bytes"
-)
-
type tagWithNode struct {
- with_pairs map[string]IEvaluator
- wrapper *NodeWrapper
+ 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() {
diff --git a/vendor/github.com/flosch/pongo2/template.go b/vendor/github.com/flosch/pongo2/template.go
index c7fe98b..869adce 100644
--- a/vendor/github.com/flosch/pongo2/template.go
+++ b/vendor/github.com/flosch/pongo2/template.go
@@ -2,52 +2,72 @@ 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
- name string
- tpl string
- size int
+ isTplString bool
+ name string
+ tpl string
+ size int
// Calculation
tokens []*Token
parser *Parser
// first come, first serve (it's important to not override existing entries in here)
- level int
- parent *Template
- child *Template
- blocks map[string]*NodeWrapper
- exported_macros map[string]*tagMacroNode
+ level int
+ parent *Template
+ child *Template
+ blocks map[string]*NodeWrapper
+ 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, "", 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,
- name: name,
- tpl: tpl,
- size: len(tpl),
- blocks: make(map[string]*NodeWrapper),
- exported_macros: make(map[string]*tagMacroNode),
+ set: set,
+ isTplString: isTplString,
+ name: name,
+ tpl: strTpl,
+ size: len(strTpl),
+ blocks: make(map[string]*NodeWrapper),
+ 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{
- Filename: tpl.name,
- Sender: "execution",
- ErrorMsg: fmt.Sprintf("Context key name '%s' clashes with macro '%s'.", k, k),
+ return &Error{
+ Filename: tpl.name,
+ Sender: "execution",
+ 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
}
diff --git a/vendor/github.com/flosch/pongo2/template_loader.go b/vendor/github.com/flosch/pongo2/template_loader.go
new file mode 100644
index 0000000..bc80f4a
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_loader.go
@@ -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 = ""
+ }()
+}
+*/
diff --git a/vendor/github.com/flosch/pongo2/template_sets.go b/vendor/github.com/flosch/pongo2/template_sets.go
index c582c5d..6b4533c 100644
--- a/vendor/github.com/flosch/pongo2/template_sets.go
+++ b/vendor/github.com/flosch/pongo2/template_sets.go
@@ -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
+ 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
- }
- name = abs
+func (set *TemplateSet) resolveFilename(tpl *Template, path string) string {
+ name := ""
+ if tpl != nil && tpl.isTplString {
+ return path
}
-
- // Check for existence
- fi, err := os.Stat(name)
- if err != nil {
- return err
+ if tpl != nil {
+ name = tpl.name
}
- if !fi.IsDir() {
- return fmt.Errorf("The given path '%s' is not a directory.")
- }
-
- set.baseDirectory = name
- return nil
+ return set.loader.Abs(name, path)
}
-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)
+ }
+ // Cache the template
+ cleanedFilename := set.resolveFilename(nil, filename)
- set.templateCacheMutex.Lock()
- defer set.templateCacheMutex.Unlock()
+ 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)
- if err != nil {
- return nil, err
- }
- set.templateCache[cleaned_filename] = tpl
- return tpl, nil
+ // Cache miss
+ if !has {
+ tpl, err := set.FromFile(cleanedFilename)
+ if err != nil {
+ return nil, err
}
-
- // Cache hit
+ set.templateCache[cleanedFilename] = tpl
return tpl, nil
}
+
+ // Cache hit
+ return tpl, nil
}
-// Loads a template from string and returns a Template instance.
+// FromString loads a template from string and returns a Template instance.
func (set *TemplateSet) FromString(tpl string) (*Template, error) {
set.firstTemplateCreated = true
+ return newTemplateString(set, []byte(tpl))
+}
+
+// FromBytes loads a template from bytes and returns a Template instance.
+func (set *TemplateSet) FromBytes(tpl []byte) (*Template, error) {
+ set.firstTemplateCreated = true
+
return newTemplateString(set, tpl)
}
-// 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(),
+ Filename: filename,
+ Sender: "fromfile",
+ OrigError: err,
}
}
- return newTemplate(set, filename, false, string(buf))
+ buf, err := ioutil.ReadAll(fd)
+ if err != nil {
+ return nil, &Error{
+ Filename: filename,
+ Sender: "fromfile",
+ OrigError: err,
+ }
+ }
+
+ return newTemplate(set, filename, false, buf)
}
-// Shortcut; renders a template string directly. Panics when providing a
-// malformed template or an error occurs during execution.
-func (set *TemplateSet) RenderTemplateString(s string, ctx Context) string {
+// 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
diff --git a/vendor/github.com/flosch/pongo2/template_tests/comment.tpl b/vendor/github.com/flosch/pongo2/template_tests/comment.tpl
new file mode 100644
index 0000000..2dac952
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/comment.tpl
@@ -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
diff --git a/vendor/github.com/flosch/pongo2/template_tests/comment.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/comment.tpl.out
new file mode 100644
index 0000000..d7acd9d
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/comment.tpl.out
@@ -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
diff --git a/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl b/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl
index 40a158a..caada14 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl
+++ b/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl
@@ -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 }}
\ No newline at end of file
+{{ 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 }}
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl.out
index be51073..d710fc8 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/expressions.tpl.out
@@ -46,8 +46,24 @@ True
False
False
True
+True
+False
+True
+True
+False
+True
+False
issue #48 (associativity for infix operators)
33
12
-0
\ No newline at end of file
+0
+
+issue #64 (uint comparison with int const)
+8
+True
+False
+True
+True
+False
+False
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl b/vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl
new file mode 100644
index 0000000..54154bd
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl
@@ -0,0 +1,3 @@
+{% extends "inheritance/base.tpl" %}
+
+{% block content %}{{ block.Super }}extends-level-1{% endblock %}
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl.out
new file mode 100644
index 0000000..7b4e8d2
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/extends_super.tpl.out
@@ -0,0 +1 @@
+Start#This is base's bodyDefault contentextends-level-1#End
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl b/vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl
new file mode 100644
index 0000000..ebac477
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl
@@ -0,0 +1,3 @@
+{% extends "extends_super.tpl" %}
+
+{% block content %}{{ block.Super }}extends-level-2{% endblock %}
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl.out
new file mode 100644
index 0000000..2284485
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/extends_super2.tpl.out
@@ -0,0 +1 @@
+Start#This is base's bodyDefault contentextends-level-1extends-level-2#End
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err b/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err
index da761b2..1fc53f2 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err
+++ b/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err
@@ -1,3 +1,4 @@
{{ -(true || false) }}
{{ simple.func_add("test", 5) }}
-{{ simple.func_variadic_sum_int("foo") }}
\ No newline at end of file
+{% for item in simple.multiple_item_list %} {{ simple.func_add("test", 5) }} {% endfor %}
+{{ simple.func_variadic_sum_int("foo") }}
diff --git a/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err.out b/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err.out
index e83ae01..a960607 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/filters-execution.err.out
@@ -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 variadic input argument of 'simple.func_variadic_sum_int' must be of type int or \*pongo2.Value \(not string\).
\ No newline at end of file
+.*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\).
diff --git a/vendor/github.com/flosch/pongo2/template_tests/filters.tpl b/vendor/github.com/flosch/pongo2/template_tests/filters.tpl
index c15468a..9cace95 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/filters.tpl
+++ b/vendor/github.com/flosch/pongo2/template_tests/filters.tpl
@@ -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" }}
diff --git a/vendor/github.com/flosch/pongo2/template_tests/filters.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/filters.tpl.out
index 1044857..5f2df13 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/filters.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/filters.tpl.out
@@ -105,7 +105,7 @@ h
first
T
-
+
@@ -113,7 +113,7 @@ T
last
t
-
+
@@ -176,6 +176,9 @@ floatformat
join
Hello, 99, 3.140000, good
+split
+Hello, 99, 3.140000, good
+
stringformat
3.14
Test: 8
diff --git a/vendor/github.com/flosch/pongo2/template_tests/for.tpl b/vendor/github.com/flosch/pongo2/template_tests/for.tpl
index 51e144c..d14e632 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/for.tpl
+++ b/vendor/github.com/flosch/pongo2/template_tests/for.tpl
@@ -6,4 +6,22 @@
{% endfor %}
reversed
-'{% for item in simple.multiple_item_list reversed %}{{ item }} {% endfor %}'
\ No newline at end of file
+'{% 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 %}'
diff --git a/vendor/github.com/flosch/pongo2/template_tests/for.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/for.tpl.out
index 18258a2..27c7120 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/for.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/for.tpl.out
@@ -16,4 +16,22 @@
reversed
-'55 34 21 13 8 5 3 2 1 1 '
\ No newline at end of file
+'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 '
diff --git a/vendor/github.com/flosch/pongo2/template_tests/if.tpl b/vendor/github.com/flosch/pongo2/template_tests/if.tpl
index c434c3f..29fe936 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/if.tpl
+++ b/vendor/github.com/flosch/pongo2/template_tests/if.tpl
@@ -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 %}
diff --git a/vendor/github.com/flosch/pongo2/template_tests/if.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/if.tpl.out
index bf931be..d4733ec 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/if.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/if.tpl.out
@@ -9,6 +9,7 @@ text field in complex.post
5 in simple.intmap
!0.0
!0
+false
42
yes
yes
diff --git a/vendor/github.com/flosch/pongo2/template_tests/includes.tpl b/vendor/github.com/flosch/pongo2/template_tests/includes.tpl
index f2b0253..2394ee9 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/includes.tpl
+++ b/vendor/github.com/flosch/pongo2/template_tests/includes.tpl
@@ -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
\ No newline at end of file
+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
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/includes.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/includes.tpl.out
index 90f7726..61d9318 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/includes.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/includes.tpl.out
@@ -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
\ No newline at end of file
+Start 'I'm guest7' End
+Start '' End
+Start '' End
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/macro-compilation.err.out b/vendor/github.com/flosch/pongo2/template_tests/macro-compilation.err.out
index a9ad8f1..0c46fba 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/macro-compilation.err.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/macro-compilation.err.out
@@ -1 +1 @@
-.*Another macro with name 'test_override' already exported.
\ No newline at end of file
+.*another macro with name 'test_override' already exported
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/macro-execution.err.out b/vendor/github.com/flosch/pongo2/template_tests/macro-execution.err.out
index 4d4067b..32cf3fb 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/macro-execution.err.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/macro-execution.err.out
@@ -1 +1 @@
-.*Context key name 'number' clashes with macro 'number'.
\ No newline at end of file
+.*context key name 'number' clashes with macro 'number'
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/pongo2ctx.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/pongo2ctx.tpl.out
index 04d0d54..9001211 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/pongo2ctx.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/pongo2ctx.tpl.out
@@ -1 +1 @@
-v3
\ No newline at end of file
+dev
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/quotes.tpl b/vendor/github.com/flosch/pongo2/template_tests/quotes.tpl
new file mode 100644
index 0000000..cb89310
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/quotes.tpl
@@ -0,0 +1,15 @@
+Variables
+{{ "hello" }}
+{{ 'hello' }}
+{{ "hell'o" }}
+
+Filters
+{{ 'Test'|slice:'1:3' }}
+{{ ''|truncatechars_html:25 }}
+{{ 'This
is a long test which will be cutted after some chars.'|truncatechars_html:25 }}
+
+Tags
+{% if 'Text' in complex.post %}text field in complex.post{% endif %}
+
+Functions
+{{ simple.func_variadic('hello') }}
diff --git a/vendor/github.com/flosch/pongo2/template_tests/quotes.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/quotes.tpl.out
new file mode 100644
index 0000000..4245893
--- /dev/null
+++ b/vendor/github.com/flosch/pongo2/template_tests/quotes.tpl.out
@@ -0,0 +1,15 @@
+Variables
+hello
+hello
+hell'o
+
+Filters
+es
+
+This
is a long test wh...
+
+Tags
+text field in complex.post
+
+Functions
+hello
diff --git a/vendor/github.com/flosch/pongo2/template_tests/set.tpl b/vendor/github.com/flosch/pongo2/template_tests/set.tpl
index 09e7b2d..3ace3be 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/set.tpl
+++ b/vendor/github.com/flosch/pongo2/template_tests/set.tpl
@@ -2,4 +2,5 @@
{% block content %}{% set new_var = "world" %}{{ new_var }}{% endblock %}
{{ new_var }}{% for item in simple.misc_list %}
{% set new_var = item %}{{ new_var }}{% endfor %}
-{{ new_var }}
\ No newline at end of file
+{{ new_var }}
+{% set car=someUndefinedVar %}{{ car.Drive }}No Panic
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/set.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/set.tpl.out
index bede53d..9d8d348 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/set.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/set.tpl.out
@@ -5,4 +5,5 @@ Hello
99
3.140000
good
-world
\ No newline at end of file
+world
+No Panic
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/template_tests/variables.tpl b/vendor/github.com/flosch/pongo2/template_tests/variables.tpl
index 2f78cae..7a0b08d 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/variables.tpl
+++ b/vendor/github.com/flosch/pongo2/template_tests/variables.tpl
@@ -10,4 +10,6 @@
{{ simple.bool_true }}
{{ simple.uint }}
{{ simple.uint|integer }}
-{{ simple.uint|float }}
\ No newline at end of file
+{{ simple.uint|float }}
+{{ simple.multiple_item_list.10 }}
+{{ simple.multiple_item_list.4 }}
diff --git a/vendor/github.com/flosch/pongo2/template_tests/variables.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/variables.tpl.out
index bdc9569..c795f10 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/variables.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/variables.tpl.out
@@ -10,4 +10,6 @@ False
True
8
8
-8.000000
\ No newline at end of file
+8.000000
+
+5
diff --git a/vendor/github.com/flosch/pongo2/template_tests/with.tpl.out b/vendor/github.com/flosch/pongo2/template_tests/with.tpl.out
index 41e3829..46686bd 100644
--- a/vendor/github.com/flosch/pongo2/template_tests/with.tpl.out
+++ b/vendor/github.com/flosch/pongo2/template_tests/with.tpl.out
@@ -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
-
+
user1
user3
\ No newline at end of file
diff --git a/vendor/github.com/flosch/pongo2/value.go b/vendor/github.com/flosch/pongo2/value.go
index 8cf8552..df70bbc 100644
--- a/vendor/github.com/flosch/pongo2/value.go
+++ b/vendor/github.com/flosch/pongo2/value.go
@@ -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,19 +393,31 @@ 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 {
+ for i := 0; i < itemCount; i++ {
+ items = append(items, &Value{val: v.getResolvedValue().Index(i)})
+ }
+
+ if sorted {
if reverse {
- for i := itemCount - 1; i >= 0; i-- {
- if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
- return
- }
- }
+ sort.Sort(sort.Reverse(items))
} else {
- for i := 0; i < itemCount; i++ {
- if !fn(i, itemCount, &Value{val: v.getResolvedValue().Index(i)}, nil) {
- return
- }
+ sort.Sort(items)
+ }
+ } else {
+ 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 {
@@ -399,7 +425,12 @@ func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, em
}
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]
+}
diff --git a/vendor/github.com/flosch/pongo2/variable.go b/vendor/github.com/flosch/pongo2/variable.go
index 9ec6a59..4a1ee69 100644
--- a/vendor/github.com/flosch/pongo2/variable.go
+++ b/vendor/github.com/flosch/pongo2/variable.go
@@ -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
- val string
+ locationToken *Token
+ val string
}
type intResolver struct {
- location_token *Token
- val int
+ locationToken *Token
+ val int
}
type floatResolver struct {
- location_token *Token
- val float64
+ locationToken *Token
+ val float64
}
type boolResolver struct {
- location_token *Token
- val bool
+ 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
- expr IEvaluator
+ 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:
- current = current.Index(part.i)
+ 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,69 +324,73 @@ 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 {
- // Function's argument has another type, using the interface-value
- parameters = append(parameters, reflect.ValueOf(pv.Interface()))
+ 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 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()))
+ 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())
}
+ // 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
@@ -377,31 +398,38 @@ func (vr *variableResolver) resolve(ctx *ExecutionContext) (*Value, error) {
}
}
+ // 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
}
}
+
+ if !current.IsValid() {
+ // Value is not valid (e. g. NIL value)
+ return AsValue(nil), nil
+ }
}
- if !current.IsValid() {
- // 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,26 +488,26 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
return nil, p.Error(err.Error(), t)
}
fr := &floatResolver{
- location_token: t,
- val: f,
+ 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,
- val: i,
- }
- return nr, nil
}
+ i, err := strconv.Atoi(t.Val)
+ if err != nil {
+ return nil, p.Error(err.Error(), t)
+ }
+ nr := &intResolver{
+ locationToken: t,
+ val: i,
+ }
+ return nr, nil
+
case TokenString:
p.Consume()
sr := &stringResolver{
- location_token: t,
- val: t.Val,
+ locationToken: t,
+ val: t.Val,
}
return sr, nil
case TokenKeyword:
@@ -487,14 +515,14 @@ func (p *Parser) parseVariableOrLiteral() (IEvaluator, *Error) {
switch t.Val {
case "true":
br := &boolResolver{
- location_token: t,
- val: true,
+ locationToken: t,
+ val: true,
}
return br, nil
case "false":
br := &boolResolver{
- location_token: t,
- val: false,
+ locationToken: t,
+ val: false,
}
return br, nil
default:
@@ -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 '{{'
diff --git a/vendor/github.com/juju/errors/.gitignore b/vendor/github.com/juju/errors/.gitignore
new file mode 100644
index 0000000..8365624
--- /dev/null
+++ b/vendor/github.com/juju/errors/.gitignore
@@ -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
diff --git a/vendor/github.com/juju/errors/LICENSE b/vendor/github.com/juju/errors/LICENSE
new file mode 100644
index 0000000..ade9307
--- /dev/null
+++ b/vendor/github.com/juju/errors/LICENSE
@@ -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.
+ 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.
diff --git a/vendor/github.com/juju/errors/Makefile b/vendor/github.com/juju/errors/Makefile
new file mode 100644
index 0000000..ab7c2e6
--- /dev/null
+++ b/vendor/github.com/juju/errors/Makefile
@@ -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
diff --git a/vendor/github.com/juju/errors/README.md b/vendor/github.com/juju/errors/README.md
new file mode 100644
index 0000000..782a6f4
--- /dev/null
+++ b/vendor/github.com/juju/errors/README.md
@@ -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)
\ No newline at end of file
diff --git a/vendor/github.com/juju/errors/doc.go b/vendor/github.com/juju/errors/doc.go
new file mode 100644
index 0000000..35b119a
--- /dev/null
+++ b/vendor/github.com/juju/errors/doc.go
@@ -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
diff --git a/vendor/github.com/juju/errors/error.go b/vendor/github.com/juju/errors/error.go
new file mode 100644
index 0000000..b7df735
--- /dev/null
+++ b/vendor/github.com/juju/errors/error.go
@@ -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)
+}
diff --git a/vendor/github.com/juju/errors/error_test.go b/vendor/github.com/juju/errors/error_test.go
new file mode 100644
index 0000000..ba9b718
--- /dev/null
+++ b/vendor/github.com/juju/errors/error_test.go
@@ -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
+}
diff --git a/vendor/github.com/juju/errors/errortypes.go b/vendor/github.com/juju/errors/errortypes.go
new file mode 100644
index 0000000..9b731c4
--- /dev/null
+++ b/vendor/github.com/juju/errors/errortypes.go
@@ -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
+}
diff --git a/vendor/github.com/juju/errors/errortypes_test.go b/vendor/github.com/juju/errors/errortypes_test.go
new file mode 100644
index 0000000..bb0ed36
--- /dev/null
+++ b/vendor/github.com/juju/errors/errortypes_test.go
@@ -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 == "" {
+ 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,
+ }, {
+ 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,
+ }, {
+ 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)
+}
diff --git a/vendor/github.com/juju/errors/example_test.go b/vendor/github.com/juju/errors/example_test.go
new file mode 100644
index 0000000..2a79cf4
--- /dev/null
+++ b/vendor/github.com/juju/errors/example_test.go
@@ -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
+ //
+}
diff --git a/vendor/github.com/juju/errors/export_test.go b/vendor/github.com/juju/errors/export_test.go
new file mode 100644
index 0000000..db57ec8
--- /dev/null
+++ b/vendor/github.com/juju/errors/export_test.go
@@ -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
diff --git a/vendor/github.com/juju/errors/functions.go b/vendor/github.com/juju/errors/functions.go
new file mode 100644
index 0000000..f86b09b
--- /dev/null
+++ b/vendor/github.com/juju/errors/functions.go
@@ -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
+}
diff --git a/vendor/github.com/juju/errors/functions_test.go b/vendor/github.com/juju/errors/functions_test.go
new file mode 100644
index 0000000..9f5a063
--- /dev/null
+++ b/vendor/github.com/juju/errors/functions_test.go
@@ -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"))
+ }
+ }
+}
diff --git a/vendor/github.com/juju/errors/package_test.go b/vendor/github.com/juju/errors/package_test.go
new file mode 100644
index 0000000..5bbb8f0
--- /dev/null
+++ b/vendor/github.com/juju/errors/package_test.go
@@ -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")
+}
diff --git a/vendor/github.com/juju/errors/path.go b/vendor/github.com/juju/errors/path.go
new file mode 100644
index 0000000..a7b726a
--- /dev/null
+++ b/vendor/github.com/juju/errors/path.go
@@ -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
+}
diff --git a/vendor/github.com/juju/errors/path_test.go b/vendor/github.com/juju/errors/path_test.go
new file mode 100644
index 0000000..ef4f34f
--- /dev/null
+++ b/vendor/github.com/juju/errors/path_test.go
@@ -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)
+}