mirror of
https://github.com/Luzifer/cloudkeys-go.git
synced 2024-11-09 14:40:05 +00:00
updated pongo to newer version
This commit is contained in:
parent
9522094655
commit
b2c7ec5e07
159 changed files with 32411 additions and 1303 deletions
40
vendor/github.com/flosch/pongo2/.gitignore
generated
vendored
40
vendor/github.com/flosch/pongo2/.gitignore
generated
vendored
|
@ -1,40 +0,0 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
.idea
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
|
||||
.project
|
||||
EBNF.txt
|
||||
test1.tpl
|
||||
pongo2_internal_test.go
|
||||
tpl-error.out
|
||||
/count.out
|
||||
/cover.out
|
||||
*.swp
|
||||
*.iml
|
||||
/cpu.out
|
||||
/mem.out
|
||||
/pongo2.test
|
||||
*.error
|
||||
/profile
|
||||
/coverage.out
|
||||
/pongo2_internal_test.ignore
|
12
vendor/github.com/flosch/pongo2/.travis.yml
generated
vendored
12
vendor/github.com/flosch/pongo2/.travis.yml
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.3
|
||||
- tip
|
||||
install:
|
||||
- go get code.google.com/p/go.tools/cmd/cover
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get gopkg.in/check.v1
|
||||
script:
|
||||
- go test -v -covermode=count -coverprofile=coverage.out -bench . -cpu 1,4
|
||||
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken $COVERALLS_TOKEN || true'
|
15
vendor/github.com/flosch/pongo2/README.md
generated
vendored
15
vendor/github.com/flosch/pongo2/README.md
generated
vendored
|
@ -1,8 +1,9 @@
|
|||
# [pongo](https://en.wikipedia.org/wiki/Pongo_%28genus%29)2
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/flosch/pongo2?status.png)](https://godoc.org/github.com/flosch/pongo2)
|
||||
[![Join the chat at https://gitter.im/flosch/pongo2](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/flosch/pongo2)
|
||||
[![GoDoc](https://godoc.org/github.com/flosch/pongo2?status.svg)](https://godoc.org/github.com/flosch/pongo2)
|
||||
[![Build Status](https://travis-ci.org/flosch/pongo2.svg?branch=master)](https://travis-ci.org/flosch/pongo2)
|
||||
[![Coverage Status](https://coveralls.io/repos/flosch/pongo2/badge.png?branch=master)](https://coveralls.io/r/flosch/pongo2?branch=master)
|
||||
[![Coverage Status](https://coveralls.io/repos/flosch/pongo2/badge.svg?branch=master)](https://coveralls.io/r/flosch/pongo2?branch=master)
|
||||
[![gratipay](http://img.shields.io/badge/gratipay-support%20pongo-brightgreen.svg)](https://gratipay.com/flosch/)
|
||||
[![Bountysource](https://www.bountysource.com/badge/tracker?tracker_id=3654947)](https://www.bountysource.com/trackers/3654947-pongo2?utm_source=3654947&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||
|
||||
|
@ -95,6 +96,7 @@ Please also have a look on the [caveats](https://github.com/flosch/pongo2#caveat
|
|||
|
||||
If you're using the `master`-branch of pongo2, you might be interested in this section. Since pongo2 is still in development (even though there is a first stable release!), there could be (backwards-incompatible) API changes over time. To keep track of these and therefore make it painless for you to adapt your codebase, I'll list them here.
|
||||
|
||||
* Function signature for tag execution changed: not taking a `bytes.Buffer` anymore; instead `Execute()`-functions are now taking a `TemplateWriter` interface.
|
||||
* Function signature for tag and filter parsing/execution changed (`error` return type changed to `*Error`).
|
||||
* `INodeEvaluator` has been removed and got replaced by `IEvaluator`. You can change your existing tags/filters by simply replacing the interface.
|
||||
* Two new helper functions: [`RenderTemplateFile()`](https://godoc.org/github.com/flosch/pongo2#RenderTemplateFile) and [`RenderTemplateString()`](https://godoc.org/github.com/flosch/pongo2#RenderTemplateString).
|
||||
|
@ -104,7 +106,7 @@ If you're using the `master`-branch of pongo2, you might be interested in this s
|
|||
## How you can help
|
||||
|
||||
* Write [filters](https://github.com/flosch/pongo2/blob/master/filters_builtin.go#L3) / [tags](https://github.com/flosch/pongo2/blob/master/tags.go#L4) (see [tutorial](https://www.florian-schlachter.de/post/pongo2/)) by forking pongo2 and sending pull requests
|
||||
* Write/improve code tests (use the following command to see what tests are missing: `go test -v -cover -covermode=count -coverprofile=cover.out && go tool cover -html=cover.out`)
|
||||
* Write/improve code tests (use the following command to see what tests are missing: `go test -v -cover -covermode=count -coverprofile=cover.out && go tool cover -html=cover.out` or have a look on [gocover.io/github.com/flosch/pongo2](http://gocover.io/github.com/flosch/pongo2))
|
||||
* Write/improve template tests (see the `template_tests/` directory)
|
||||
* Write middleware, libraries and websites using pongo2. :-)
|
||||
|
||||
|
@ -116,6 +118,7 @@ You can access pongo2's API documentation on [godoc](https://godoc.org/github.co
|
|||
|
||||
## Blog post series
|
||||
|
||||
* [pongo2 v3 released](https://www.florian-schlachter.de/post/pongo2-v3/)
|
||||
* [pongo2 v2 released](https://www.florian-schlachter.de/post/pongo2-v2/)
|
||||
* [pongo2 1.0 released](https://www.florian-schlachter.de/post/pongo2-10/) [August 8th 2014]
|
||||
* [pongo2 playground](https://www.florian-schlachter.de/post/pongo2-playground/) [August 1st 2014]
|
||||
|
@ -154,7 +157,11 @@ You can access pongo2's API documentation on [godoc](https://godoc.org/github.co
|
|||
* [beego-pongo2.v2](https://github.com/ipfans/beego-pongo2.v2) - Same as `beego-pongo2`, but for pongo2 v2.
|
||||
* [macaron-pongo2](https://github.com/macaron-contrib/pongo2) - pongo2 support for [Macaron](https://github.com/Unknwon/macaron), a modular web framework.
|
||||
* [ginpongo2](https://github.com/ngerakines/ginpongo2) - middleware for [gin](github.com/gin-gonic/gin) to use pongo2 templates
|
||||
* [pongo2-trans](https://github.com/fromYukki/pongo2trans) - `trans`-tag implementation for internationalization
|
||||
* [Build'n support for Iris' template engine](https://github.com/kataras/iris)
|
||||
* [pongo2gin](https://github.com/robvdl/pongo2gin) - alternative renderer for [gin](github.com/gin-gonic/gin) to use pongo2 templates
|
||||
* [pongo2-trans](https://github.com/digitalcrab/pongo2trans) - `trans`-tag implementation for internationalization
|
||||
* [tpongo2](https://github.com/tango-contrib/tpongo2) - pongo2 support for [Tango](https://github.com/lunny/tango), a micro-kernel & pluggable web framework.
|
||||
* [p2cli](https://github.com/wrouesnel/p2cli) - command line templating utility based on pongo2
|
||||
|
||||
Please add your project to this list and send me a pull request when you've developed something nice for pongo2.
|
||||
|
||||
|
|
30
vendor/github.com/flosch/pongo2/context.go
generated
vendored
30
vendor/github.com/flosch/pongo2/context.go
generated
vendored
|
@ -1,13 +1,14 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
var reIdentifiers = regexp.MustCompile("^[a-zA-Z0-9_]+$")
|
||||
|
||||
// Use this Context type to provide constants, variables, instances or functions to your template.
|
||||
// A Context type provides constants, variables, instances or functions to a template.
|
||||
//
|
||||
// pongo2 automatically provides meta-information or functions through the "pongo2"-key.
|
||||
// Currently, context["pongo2"] contains the following keys:
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
37
vendor/github.com/flosch/pongo2/error.go
generated
vendored
37
vendor/github.com/flosch/pongo2/error.go
generated
vendored
|
@ -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 == "<string>" {
|
||||
return "", false
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
filename := e.Filename
|
||||
|
@ -70,17 +70,22 @@ func (e *Error) RawLine() (line string, available bool) {
|
|||
}
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return "", false, err
|
||||
}
|
||||
defer file.Close()
|
||||
defer func() {
|
||||
err := file.Close()
|
||||
if err != nil && outErr == nil {
|
||||
outErr = err
|
||||
}
|
||||
}()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
l := 0
|
||||
for scanner.Scan() {
|
||||
l++
|
||||
if l == e.Line {
|
||||
return scanner.Text(), true
|
||||
return scanner.Text(), true, nil
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
return "", false, nil
|
||||
}
|
||||
|
|
54
vendor/github.com/flosch/pongo2/filters.go
generated
vendored
54
vendor/github.com/flosch/pongo2/filters.go
generated
vendored
|
@ -2,8 +2,11 @@ package pongo2
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// FilterFunction is the type filter functions must fulfil
|
||||
type FilterFunction func(in *Value, param *Value) (out *Value, err *Error)
|
||||
|
||||
var filters map[string]FilterFunction
|
||||
|
@ -12,32 +15,38 @@ func init() {
|
|||
filters = make(map[string]FilterFunction)
|
||||
}
|
||||
|
||||
// Registers a new filter. If there's already a filter with the same
|
||||
// FilterExists returns true if the given filter is already registered
|
||||
func FilterExists(name string) bool {
|
||||
_, existing := filters[name]
|
||||
return existing
|
||||
}
|
||||
|
||||
// RegisterFilter registers a new filter. If there's already a filter with the same
|
||||
// name, RegisterFilter will panic. You usually want to call this
|
||||
// function in the filter's init() function:
|
||||
// http://golang.org/doc/effective_go.html#init
|
||||
//
|
||||
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
||||
// writing filters and tags.
|
||||
func RegisterFilter(name string, fn FilterFunction) {
|
||||
_, existing := filters[name]
|
||||
if existing {
|
||||
panic(fmt.Sprintf("Filter with name '%s' is already registered.", name))
|
||||
func RegisterFilter(name string, fn FilterFunction) error {
|
||||
if FilterExists(name) {
|
||||
return errors.Errorf("filter with name '%s' is already registered", name)
|
||||
}
|
||||
filters[name] = fn
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replaces an already registered filter with a new implementation. Use this
|
||||
// ReplaceFilter replaces an already registered filter with a new implementation. Use this
|
||||
// function with caution since it allows you to change existing filter behaviour.
|
||||
func ReplaceFilter(name string, fn FilterFunction) {
|
||||
_, existing := filters[name]
|
||||
if !existing {
|
||||
panic(fmt.Sprintf("Filter with name '%s' does not exist (therefore cannot be overridden).", name))
|
||||
func ReplaceFilter(name string, fn FilterFunction) error {
|
||||
if !FilterExists(name) {
|
||||
return errors.Errorf("filter with name '%s' does not exist (therefore cannot be overridden)", name)
|
||||
}
|
||||
filters[name] = fn
|
||||
return nil
|
||||
}
|
||||
|
||||
// Like ApplyFilter, but panics on an error
|
||||
// MustApplyFilter behaves like ApplyFilter, but panics on an error.
|
||||
func MustApplyFilter(name string, value *Value, param *Value) *Value {
|
||||
val, err := ApplyFilter(name, value, param)
|
||||
if err != nil {
|
||||
|
@ -46,13 +55,14 @@ func MustApplyFilter(name string, value *Value, param *Value) *Value {
|
|||
return val
|
||||
}
|
||||
|
||||
// Applies a filter to a given value using the given parameters. Returns a *pongo2.Value or an error.
|
||||
// ApplyFilter applies a filter to a given value using the given parameters.
|
||||
// Returns a *pongo2.Value or an error.
|
||||
func ApplyFilter(name string, value *Value, param *Value) (*Value, *Error) {
|
||||
fn, existing := filters[name]
|
||||
if !existing {
|
||||
return nil, &Error{
|
||||
Sender: "applyfilter",
|
||||
ErrorMsg: fmt.Sprintf("Filter with name '%s' not found.", name),
|
||||
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
|
||||
|
|
178
vendor/github.com/flosch/pongo2/filters_builtin.go
generated
vendored
178
vendor/github.com/flosch/pongo2/filters_builtin.go
generated
vendored
|
@ -35,6 +35,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -73,14 +75,15 @@ func init() {
|
|||
RegisterFilter("removetags", filterRemovetags)
|
||||
RegisterFilter("rjust", filterRjust)
|
||||
RegisterFilter("slice", filterSlice)
|
||||
RegisterFilter("split", filterSplit)
|
||||
RegisterFilter("stringformat", filterStringformat)
|
||||
RegisterFilter("striptags", filterStriptags)
|
||||
RegisterFilter("time", filterDate) // time uses filterDate (same golang-format)
|
||||
RegisterFilter("title", filterTitle)
|
||||
RegisterFilter("truncatechars", filterTruncatechars)
|
||||
RegisterFilter("truncatechars_html", filterTruncatecharsHtml)
|
||||
RegisterFilter("truncatechars_html", filterTruncatecharsHTML)
|
||||
RegisterFilter("truncatewords", filterTruncatewords)
|
||||
RegisterFilter("truncatewords_html", filterTruncatewordsHtml)
|
||||
RegisterFilter("truncatewords_html", filterTruncatewordsHTML)
|
||||
RegisterFilter("upper", filterUpper)
|
||||
RegisterFilter("urlencode", filterUrlencode)
|
||||
RegisterFilter("urlize", filterUrlize)
|
||||
|
@ -105,9 +108,9 @@ func filterTruncatecharsHelper(s string, newLen int) string {
|
|||
return string(runes)
|
||||
}
|
||||
|
||||
func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func() bool, fn func(c rune, s int, idx int) int, finalize func()) {
|
||||
func filterTruncateHTMLHelper(value string, newOutput *bytes.Buffer, cond func() bool, fn func(c rune, s int, idx int) int, finalize func()) {
|
||||
vLen := len(value)
|
||||
tag_stack := make([]string, 0)
|
||||
var tagStack []string
|
||||
idx := 0
|
||||
|
||||
for idx < vLen && !cond() {
|
||||
|
@ -118,17 +121,17 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
}
|
||||
|
||||
if c == '<' {
|
||||
new_output.WriteRune(c)
|
||||
newOutput.WriteRune(c)
|
||||
idx += s // consume "<"
|
||||
|
||||
if idx+1 < vLen {
|
||||
if value[idx] == '/' {
|
||||
// Close tag
|
||||
|
||||
new_output.WriteString("/")
|
||||
newOutput.WriteString("/")
|
||||
|
||||
tag := ""
|
||||
idx += 1 // consume "/"
|
||||
idx++ // consume "/"
|
||||
|
||||
for idx < vLen {
|
||||
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
||||
|
@ -146,21 +149,21 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
idx += size2
|
||||
}
|
||||
|
||||
if len(tag_stack) > 0 {
|
||||
if len(tagStack) > 0 {
|
||||
// Ideally, the close tag is TOP of tag stack
|
||||
// In malformed HTML, it must not be, so iterate through the stack and remove the tag
|
||||
for i := len(tag_stack) - 1; i >= 0; i-- {
|
||||
if tag_stack[i] == tag {
|
||||
for i := len(tagStack) - 1; i >= 0; i-- {
|
||||
if tagStack[i] == tag {
|
||||
// Found the tag
|
||||
tag_stack[i] = tag_stack[len(tag_stack)-1]
|
||||
tag_stack = tag_stack[:len(tag_stack)-1]
|
||||
tagStack[i] = tagStack[len(tagStack)-1]
|
||||
tagStack = tagStack[:len(tagStack)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_output.WriteString(tag)
|
||||
new_output.WriteString(">")
|
||||
newOutput.WriteString(tag)
|
||||
newOutput.WriteString(">")
|
||||
} else {
|
||||
// Open tag
|
||||
|
||||
|
@ -174,7 +177,7 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
continue
|
||||
}
|
||||
|
||||
new_output.WriteRune(c2)
|
||||
newOutput.WriteRune(c2)
|
||||
|
||||
// End of tag found
|
||||
if c2 == '>' {
|
||||
|
@ -194,7 +197,7 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
}
|
||||
|
||||
// Add tag to stack
|
||||
tag_stack = append(tag_stack, tag)
|
||||
tagStack = append(tagStack, tag)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -204,10 +207,10 @@ func filterTruncateHtmlHelper(value string, new_output *bytes.Buffer, cond func(
|
|||
|
||||
finalize()
|
||||
|
||||
for i := len(tag_stack) - 1; i >= 0; i-- {
|
||||
tag := tag_stack[i]
|
||||
for i := len(tagStack) - 1; i >= 0; i-- {
|
||||
tag := tagStack[i]
|
||||
// Close everything from the regular tag stack
|
||||
new_output.WriteString(fmt.Sprintf("</%s>", tag))
|
||||
newOutput.WriteString(fmt.Sprintf("</%s>", tag))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,28 +220,28 @@ func filterTruncatechars(in *Value, param *Value) (*Value, *Error) {
|
|||
return AsValue(filterTruncatecharsHelper(s, newLen)), nil
|
||||
}
|
||||
|
||||
func filterTruncatecharsHtml(in *Value, param *Value) (*Value, *Error) {
|
||||
func filterTruncatecharsHTML(in *Value, param *Value) (*Value, *Error) {
|
||||
value := in.String()
|
||||
newLen := max(param.Integer()-3, 0)
|
||||
|
||||
new_output := bytes.NewBuffer(nil)
|
||||
newOutput := bytes.NewBuffer(nil)
|
||||
|
||||
textcounter := 0
|
||||
|
||||
filterTruncateHtmlHelper(value, new_output, func() bool {
|
||||
filterTruncateHTMLHelper(value, newOutput, func() bool {
|
||||
return textcounter >= newLen
|
||||
}, func(c rune, s int, idx int) int {
|
||||
textcounter++
|
||||
new_output.WriteRune(c)
|
||||
newOutput.WriteRune(c)
|
||||
|
||||
return idx + s
|
||||
}, func() {
|
||||
if textcounter >= newLen && textcounter < len(value) {
|
||||
new_output.WriteString("...")
|
||||
newOutput.WriteString("...")
|
||||
}
|
||||
})
|
||||
|
||||
return AsSafeValue(new_output.String()), nil
|
||||
return AsSafeValue(newOutput.String()), nil
|
||||
}
|
||||
|
||||
func filterTruncatewords(in *Value, param *Value) (*Value, *Error) {
|
||||
|
@ -260,19 +263,19 @@ func filterTruncatewords(in *Value, param *Value) (*Value, *Error) {
|
|||
return AsValue(strings.Join(out, " ")), nil
|
||||
}
|
||||
|
||||
func filterTruncatewordsHtml(in *Value, param *Value) (*Value, *Error) {
|
||||
func filterTruncatewordsHTML(in *Value, param *Value) (*Value, *Error) {
|
||||
value := in.String()
|
||||
newLen := max(param.Integer(), 0)
|
||||
|
||||
new_output := bytes.NewBuffer(nil)
|
||||
newOutput := bytes.NewBuffer(nil)
|
||||
|
||||
wordcounter := 0
|
||||
|
||||
filterTruncateHtmlHelper(value, new_output, func() bool {
|
||||
filterTruncateHTMLHelper(value, newOutput, func() bool {
|
||||
return wordcounter >= newLen
|
||||
}, func(_ rune, _ int, idx int) int {
|
||||
// Get next word
|
||||
word_found := false
|
||||
wordFound := false
|
||||
|
||||
for idx < len(value) {
|
||||
c2, size2 := utf8.DecodeRuneInString(value[idx:])
|
||||
|
@ -286,29 +289,29 @@ func filterTruncatewordsHtml(in *Value, param *Value) (*Value, *Error) {
|
|||
return idx
|
||||
}
|
||||
|
||||
new_output.WriteRune(c2)
|
||||
newOutput.WriteRune(c2)
|
||||
idx += size2
|
||||
|
||||
if c2 == ' ' || c2 == '.' || c2 == ',' || c2 == ';' {
|
||||
// Word ends here, stop capturing it now
|
||||
break
|
||||
} else {
|
||||
word_found = true
|
||||
wordFound = true
|
||||
}
|
||||
}
|
||||
|
||||
if word_found {
|
||||
if wordFound {
|
||||
wordcounter++
|
||||
}
|
||||
|
||||
return idx
|
||||
}, func() {
|
||||
if wordcounter >= newLen {
|
||||
new_output.WriteString("...")
|
||||
newOutput.WriteString("...")
|
||||
}
|
||||
})
|
||||
|
||||
return AsSafeValue(new_output.String()), nil
|
||||
return AsSafeValue(newOutput.String()), nil
|
||||
}
|
||||
|
||||
func filterEscape(in *Value, param *Value) (*Value, *Error) {
|
||||
|
@ -377,12 +380,11 @@ func filterAdd(in *Value, param *Value) (*Value, *Error) {
|
|||
if in.IsNumber() && param.IsNumber() {
|
||||
if in.IsFloat() || param.IsFloat() {
|
||||
return AsValue(in.Float() + param.Float()), nil
|
||||
} else {
|
||||
return AsValue(in.Integer() + param.Integer()), nil
|
||||
}
|
||||
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", "<br />", -1)), nil
|
||||
}
|
||||
|
@ -641,7 +649,8 @@ func filterUrlencode(in *Value, param *Value) (*Value, *Error) {
|
|||
var filterUrlizeURLRegexp = regexp.MustCompile(`((((http|https)://)|www\.|((^|[ ])[0-9A-Za-z_\-]+(\.com|\.net|\.org|\.info|\.biz|\.de))))(?U:.*)([ ]+|$)`)
|
||||
var filterUrlizeEmailRegexp = regexp.MustCompile(`(\w+@\w+\.\w{2,4})`)
|
||||
|
||||
func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
||||
func filterUrlizeHelper(input string, autoescape bool, trunc int) (string, error) {
|
||||
var soutErr error
|
||||
sout := filterUrlizeURLRegexp.ReplaceAllStringFunc(input, func(raw_url string) string {
|
||||
var prefix string
|
||||
var suffix string
|
||||
|
@ -656,7 +665,8 @@ func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
|||
|
||||
t, err := ApplyFilter("iriencode", AsValue(raw_url), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
soutErr = err
|
||||
return ""
|
||||
}
|
||||
url := t.String()
|
||||
|
||||
|
@ -673,16 +683,19 @@ func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
|||
if autoescape {
|
||||
t, err := ApplyFilter("escape", AsValue(title), nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
soutErr = err
|
||||
return ""
|
||||
}
|
||||
title = t.String()
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`%s<a href="%s" rel="nofollow">%s</a>%s`, prefix, url, title, suffix)
|
||||
})
|
||||
if soutErr != nil {
|
||||
return "", soutErr
|
||||
}
|
||||
|
||||
sout = filterUrlizeEmailRegexp.ReplaceAllStringFunc(sout, func(mail string) string {
|
||||
|
||||
title := mail
|
||||
|
||||
if trunc > 3 && len(title) > trunc {
|
||||
|
@ -692,7 +705,7 @@ func filterUrlizeHelper(input string, autoescape bool, trunc int) string {
|
|||
return fmt.Sprintf(`<a href="mailto:%s">%s</a>`, mail, title)
|
||||
})
|
||||
|
||||
return sout
|
||||
return sout, nil
|
||||
}
|
||||
|
||||
func filterUrlize(in *Value, param *Value) (*Value, *Error) {
|
||||
|
@ -701,24 +714,36 @@ func filterUrlize(in *Value, param *Value) (*Value, *Error) {
|
|||
autoescape = param.Bool()
|
||||
}
|
||||
|
||||
return AsValue(filterUrlizeHelper(in.String(), autoescape, -1)), nil
|
||||
s, err := filterUrlizeHelper(in.String(), autoescape, -1)
|
||||
if err != nil {
|
||||
|
||||
}
|
||||
|
||||
return AsValue(s), nil
|
||||
}
|
||||
|
||||
func filterUrlizetrunc(in *Value, param *Value) (*Value, *Error) {
|
||||
return AsValue(filterUrlizeHelper(in.String(), true, param.Integer())), nil
|
||||
s, err := filterUrlizeHelper(in.String(), true, param.Integer())
|
||||
if err != nil {
|
||||
return nil, &Error{
|
||||
Sender: "filter:urlizetrunc",
|
||||
OrigError: errors.New("you cannot pass more than 2 arguments to filter 'pluralize'"),
|
||||
}
|
||||
}
|
||||
return AsValue(s), nil
|
||||
}
|
||||
|
||||
func filterStringformat(in *Value, param *Value) (*Value, *Error) {
|
||||
return AsValue(fmt.Sprintf(param.String(), in.Interface())), nil
|
||||
}
|
||||
|
||||
var re_striptags = regexp.MustCompile("<[^>]*?>")
|
||||
var reStriptags = regexp.MustCompile("<[^>]*?>")
|
||||
|
||||
func filterStriptags(in *Value, param *Value) (*Value, *Error) {
|
||||
s := in.String()
|
||||
|
||||
// Strip all tags
|
||||
s = re_striptags.ReplaceAllString(s, "")
|
||||
s = reStriptags.ReplaceAllString(s, "")
|
||||
|
||||
return AsValue(strings.TrimSpace(s)), nil
|
||||
}
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
44
vendor/github.com/flosch/pongo2/lexer.go
generated
vendored
44
vendor/github.com/flosch/pongo2/lexer.go
generated
vendored
|
@ -4,6 +4,8 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -63,8 +65,8 @@ type lexer struct {
|
|||
line int
|
||||
col int
|
||||
|
||||
in_verbatim bool
|
||||
verbatim_name string
|
||||
inVerbatim bool
|
||||
verbatimName string
|
||||
}
|
||||
|
||||
func (t *Token) String() string {
|
||||
|
@ -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
|
||||
|
|
8
vendor/github.com/flosch/pongo2/nodes.go
generated
vendored
8
vendor/github.com/flosch/pongo2/nodes.go
generated
vendored
|
@ -1,17 +1,13 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// The root document
|
||||
type nodeDocument struct {
|
||||
Nodes []INode
|
||||
}
|
||||
|
||||
func (doc *nodeDocument) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (doc *nodeDocument) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
for _, n := range doc.Nodes {
|
||||
err := n.Execute(ctx, buffer)
|
||||
err := n.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
8
vendor/github.com/flosch/pongo2/nodes_html.go
generated
vendored
8
vendor/github.com/flosch/pongo2/nodes_html.go
generated
vendored
|
@ -1,14 +1,10 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type nodeHTML struct {
|
||||
token *Token
|
||||
}
|
||||
|
||||
func (n *nodeHTML) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
buffer.WriteString(n.token.Val)
|
||||
func (n *nodeHTML) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
writer.WriteString(n.token.Val)
|
||||
return nil
|
||||
}
|
||||
|
|
8
vendor/github.com/flosch/pongo2/nodes_wrapper.go
generated
vendored
8
vendor/github.com/flosch/pongo2/nodes_wrapper.go
generated
vendored
|
@ -1,17 +1,13 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type NodeWrapper struct {
|
||||
Endtag string
|
||||
nodes []INode
|
||||
}
|
||||
|
||||
func (wrapper *NodeWrapper) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (wrapper *NodeWrapper) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
for _, n := range wrapper.nodes {
|
||||
err := n.Execute(ctx, buffer)
|
||||
err := n.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
98
vendor/github.com/flosch/pongo2/parser.go
generated
vendored
98
vendor/github.com/flosch/pongo2/parser.go
generated
vendored
|
@ -1,13 +1,14 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type INode interface {
|
||||
Execute(*ExecutionContext, *bytes.Buffer) *Error
|
||||
Execute(*ExecutionContext, TemplateWriter) *Error
|
||||
}
|
||||
|
||||
type IEvaluator interface {
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
156
vendor/github.com/flosch/pongo2/parser_expression.go
generated
vendored
156
vendor/github.com/flosch/pongo2/parser_expression.go
generated
vendored
|
@ -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 {
|
||||
|
|
6
vendor/github.com/flosch/pongo2/pongo2.go
generated
vendored
6
vendor/github.com/flosch/pongo2/pongo2.go
generated
vendored
|
@ -1,10 +1,10 @@
|
|||
package pongo2
|
||||
|
||||
// Version string
|
||||
const Version = "v3"
|
||||
const Version = "dev"
|
||||
|
||||
// Helper function which panics, if a Template couldn't
|
||||
// successfully parsed. This is how you would use it:
|
||||
// Must panics, if a Template couldn't successfully parsed. This is how you
|
||||
// would use it:
|
||||
// var baseTemplate = pongo2.Must(pongo2.FromFile("templates/base.html"))
|
||||
func Must(tpl *Template, err error) *Template {
|
||||
if err != nil {
|
||||
|
|
31
vendor/github.com/flosch/pongo2/pongo2_issues_test.go
generated
vendored
31
vendor/github.com/flosch/pongo2/pongo2_issues_test.go
generated
vendored
|
@ -1,20 +1,29 @@
|
|||
package pongo2
|
||||
package pongo2_test
|
||||
|
||||
import (
|
||||
"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)
|
||||
}
|
||||
}
|
||||
|
|
201
vendor/github.com/flosch/pongo2/pongo2_template_test.go
generated
vendored
201
vendor/github.com/flosch/pongo2/pongo2_template_test.go
generated
vendored
|
@ -1,4 +1,4 @@
|
|||
package pongo2
|
||||
package pongo2_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -9,9 +9,11 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/flosch/pongo2"
|
||||
)
|
||||
|
||||
var admin_list = []string{"user2"}
|
||||
var adminList = []string{"user2"}
|
||||
|
||||
var time1 = time.Date(2014, 06, 10, 15, 30, 15, 0, time.UTC)
|
||||
var time2 = time.Date(2011, 03, 21, 8, 37, 56, 12, time.UTC)
|
||||
|
@ -32,8 +34,8 @@ type comment struct {
|
|||
Text string
|
||||
}
|
||||
|
||||
func is_admin(u *user) bool {
|
||||
for _, a := range admin_list {
|
||||
func isAdmin(u *user) bool {
|
||||
for _, a := range adminList {
|
||||
if a == u.Name {
|
||||
return true
|
||||
}
|
||||
|
@ -41,12 +43,12 @@ func is_admin(u *user) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (u *user) Is_admin() *Value {
|
||||
return AsValue(is_admin(u))
|
||||
func (u *user) Is_admin() *pongo2.Value {
|
||||
return pongo2.AsValue(isAdmin(u))
|
||||
}
|
||||
|
||||
func (u *user) Is_admin2() bool {
|
||||
return is_admin(u)
|
||||
return isAdmin(u)
|
||||
}
|
||||
|
||||
func (p *post) String() string {
|
||||
|
@ -60,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": "<script>alert(\"uh oh\");</script>",
|
||||
"intmap": map[int]string{
|
||||
1: "one",
|
||||
2: "two",
|
||||
5: "five",
|
||||
2: "two",
|
||||
},
|
||||
"strmap": map[string]string{
|
||||
"abc": "def",
|
||||
"bcd": "efg",
|
||||
"zab": "cde",
|
||||
"gh": "kqm",
|
||||
"ukq": "qqa",
|
||||
"aab": "aba",
|
||||
},
|
||||
"func_add": func(a, b int) int {
|
||||
return a + b
|
||||
|
@ -167,17 +158,17 @@ Yep!`,
|
|||
}
|
||||
return s
|
||||
},
|
||||
"func_variadic_sum_int2": func(args ...*Value) *Value {
|
||||
"func_variadic_sum_int2": func(args ...*pongo2.Value) *pongo2.Value {
|
||||
// Create a sum
|
||||
s := 0
|
||||
for _, i := range args {
|
||||
s += i.Integer()
|
||||
}
|
||||
return AsValue(s)
|
||||
return pongo2.AsValue(s)
|
||||
},
|
||||
},
|
||||
"complex": map[string]interface{}{
|
||||
"is_admin": is_admin,
|
||||
"is_admin": isAdmin,
|
||||
"post": post{
|
||||
Text: "<h2>Hello!</h2><p>Welcome to my new blog page. I'm using pongo2 which supports {{ variables }} and {% tags %}.</p>",
|
||||
Created: time2,
|
||||
|
@ -238,10 +229,8 @@ Yep!`,
|
|||
}
|
||||
|
||||
func TestTemplates(t *testing.T) {
|
||||
debug = true
|
||||
|
||||
// Add a global to the default set
|
||||
Globals["this_is_a_global_variable"] = "this is a global text"
|
||||
pongo2.Globals["this_is_a_global_variable"] = "this is a global text"
|
||||
|
||||
matches, err := filepath.Glob("./template_tests/*.tpl")
|
||||
if err != nil {
|
||||
|
@ -249,34 +238,34 @@ func TestTemplates(t *testing.T) {
|
|||
}
|
||||
for idx, match := range matches {
|
||||
t.Logf("[Template %3d] Testing '%s'", idx+1, match)
|
||||
tpl, err := FromFile(match)
|
||||
tpl, err := pongo2.FromFile(match)
|
||||
if err != nil {
|
||||
t.Fatalf("Error on FromFile('%s'): %s", match, err.Error())
|
||||
}
|
||||
test_filename := fmt.Sprintf("%s.out", match)
|
||||
test_out, rerr := ioutil.ReadFile(test_filename)
|
||||
testFilename := fmt.Sprintf("%s.out", match)
|
||||
testOut, rerr := ioutil.ReadFile(testFilename)
|
||||
if rerr != nil {
|
||||
t.Fatalf("Error on ReadFile('%s'): %s", test_filename, rerr.Error())
|
||||
t.Fatalf("Error on ReadFile('%s'): %s", testFilename, rerr.Error())
|
||||
}
|
||||
tpl_out, err := tpl.ExecuteBytes(tplContext)
|
||||
tplOut, err := tpl.ExecuteBytes(tplContext)
|
||||
if err != nil {
|
||||
t.Fatalf("Error on Execute('%s'): %s", match, err.Error())
|
||||
}
|
||||
if bytes.Compare(test_out, tpl_out) != 0 {
|
||||
t.Logf("Template (rendered) '%s': '%s'", match, tpl_out)
|
||||
err_filename := filepath.Base(fmt.Sprintf("%s.error", match))
|
||||
err := ioutil.WriteFile(err_filename, []byte(tpl_out), 0600)
|
||||
if bytes.Compare(testOut, tplOut) != 0 {
|
||||
t.Logf("Template (rendered) '%s': '%s'", match, tplOut)
|
||||
errFilename := filepath.Base(fmt.Sprintf("%s.error", match))
|
||||
err := ioutil.WriteFile(errFilename, []byte(tplOut), 0600)
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
t.Logf("get a complete diff with command: 'diff -ya %s %s'", test_filename, err_filename)
|
||||
t.Logf("get a complete diff with command: 'diff -ya %s %s'", testFilename, errFilename)
|
||||
t.Errorf("Failed: test_out != tpl_out for %s", match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecutionErrors(t *testing.T) {
|
||||
debug = true
|
||||
//debug = true
|
||||
|
||||
matches, err := filepath.Glob("./template_tests/*-execution.err")
|
||||
if err != nil {
|
||||
|
@ -285,15 +274,15 @@ func TestExecutionErrors(t *testing.T) {
|
|||
for idx, match := range matches {
|
||||
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
||||
|
||||
test_data, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(test_data), "\n")
|
||||
testData, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(testData), "\n")
|
||||
|
||||
check_filename := fmt.Sprintf("%s.out", match)
|
||||
check_data, err := ioutil.ReadFile(check_filename)
|
||||
checkFilename := fmt.Sprintf("%s.out", match)
|
||||
checkData, err := ioutil.ReadFile(checkFilename)
|
||||
if err != nil {
|
||||
t.Fatalf("Error on ReadFile('%s'): %s", check_filename, err.Error())
|
||||
t.Fatalf("Error on ReadFile('%s'): %s", checkFilename, err.Error())
|
||||
}
|
||||
checks := strings.Split(string(check_data), "\n")
|
||||
checks := strings.Split(string(checkData), "\n")
|
||||
|
||||
if len(checks) != len(tests) {
|
||||
t.Fatal("Template lines != Checks lines")
|
||||
|
@ -308,11 +297,16 @@ func TestExecutionErrors(t *testing.T) {
|
|||
match, idx+1)
|
||||
}
|
||||
|
||||
tpl, err := FromString(test)
|
||||
tpl, err := pongo2.FromString(test)
|
||||
if err != nil {
|
||||
t.Fatalf("Error on FromString('%s'): %s", test, err.Error())
|
||||
}
|
||||
|
||||
tpl, err = pongo2.FromBytes([]byte(test))
|
||||
if err != nil {
|
||||
t.Fatalf("Error on FromBytes('%s'): %s", test, err.Error())
|
||||
}
|
||||
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
if err == nil {
|
||||
t.Fatalf("[%s Line %d] Expected error for (got none): %s",
|
||||
|
@ -329,7 +323,7 @@ func TestExecutionErrors(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCompilationErrors(t *testing.T) {
|
||||
debug = true
|
||||
//debug = true
|
||||
|
||||
matches, err := filepath.Glob("./template_tests/*-compilation.err")
|
||||
if err != nil {
|
||||
|
@ -338,15 +332,15 @@ func TestCompilationErrors(t *testing.T) {
|
|||
for idx, match := range matches {
|
||||
t.Logf("[Errors %3d] Testing '%s'", idx+1, match)
|
||||
|
||||
test_data, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(test_data), "\n")
|
||||
testData, err := ioutil.ReadFile(match)
|
||||
tests := strings.Split(string(testData), "\n")
|
||||
|
||||
check_filename := fmt.Sprintf("%s.out", match)
|
||||
check_data, err := ioutil.ReadFile(check_filename)
|
||||
checkFilename := fmt.Sprintf("%s.out", match)
|
||||
checkData, err := ioutil.ReadFile(checkFilename)
|
||||
if err != nil {
|
||||
t.Fatalf("Error on ReadFile('%s'): %s", check_filename, err.Error())
|
||||
t.Fatalf("Error on ReadFile('%s'): %s", checkFilename, err.Error())
|
||||
}
|
||||
checks := strings.Split(string(check_data), "\n")
|
||||
checks := strings.Split(string(checkData), "\n")
|
||||
|
||||
if len(checks) != len(tests) {
|
||||
t.Fatal("Template lines != Checks lines")
|
||||
|
@ -361,7 +355,7 @@ func TestCompilationErrors(t *testing.T) {
|
|||
match, idx+1)
|
||||
}
|
||||
|
||||
_, err = FromString(test)
|
||||
_, err = pongo2.FromString(test)
|
||||
if err == nil {
|
||||
t.Fatalf("[%s | Line %d] Expected error for (got none): %s", match, idx+1, tests[idx])
|
||||
}
|
||||
|
@ -377,9 +371,10 @@ func TestCompilationErrors(t *testing.T) {
|
|||
func TestBaseDirectory(t *testing.T) {
|
||||
mustStr := "Hello from template_tests/base_dir_test/"
|
||||
|
||||
s := NewSet("test set with base directory")
|
||||
fs := pongo2.MustNewLocalFileSystemLoader("")
|
||||
s := pongo2.NewSet("test set with base directory", fs)
|
||||
s.Globals["base_directory"] = "template_tests/base_dir_test/"
|
||||
if err := s.SetBaseDirectory(s.Globals["base_directory"].(string)); err != nil {
|
||||
if err := fs.SetBaseDir(s.Globals["base_directory"].(string)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -405,13 +400,13 @@ func TestBaseDirectory(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkCache(b *testing.B) {
|
||||
cache_set := NewSet("cache set")
|
||||
cacheSet := pongo2.NewSet("cache set", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
for i := 0; i < b.N; i++ {
|
||||
tpl, err := cache_set.FromCache("template_tests/complex.tpl")
|
||||
tpl, err := cacheSet.FromCache("template_tests/complex.tpl")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -419,14 +414,14 @@ func BenchmarkCache(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkCacheDebugOn(b *testing.B) {
|
||||
cache_debug_set := NewSet("cache set")
|
||||
cache_debug_set.Debug = true
|
||||
cacheDebugSet := pongo2.NewSet("cache set", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
cacheDebugSet.Debug = true
|
||||
for i := 0; i < b.N; i++ {
|
||||
tpl, err := cache_debug_set.FromFile("template_tests/complex.tpl")
|
||||
tpl, err := cacheDebugSet.FromFile("template_tests/complex.tpl")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -434,13 +429,13 @@ func BenchmarkCacheDebugOn(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkExecuteComplexWithSandboxActive(b *testing.B) {
|
||||
tpl, err := FromFile("template_tests/complex.tpl")
|
||||
tpl, err := pongo2.FromFile("template_tests/complex.tpl")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -455,12 +450,12 @@ func BenchmarkCompileAndExecuteComplexWithSandboxActive(b *testing.B) {
|
|||
preloadedTpl := string(buf)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
tpl, err := FromString(preloadedTpl)
|
||||
tpl, err := pongo2.FromString(preloadedTpl)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -468,14 +463,14 @@ func BenchmarkCompileAndExecuteComplexWithSandboxActive(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkParallelExecuteComplexWithSandboxActive(b *testing.B) {
|
||||
tpl, err := FromFile("template_tests/complex.tpl")
|
||||
tpl, err := pongo2.FromFile("template_tests/complex.tpl")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, err := tpl.ExecuteBytes(tplContext)
|
||||
err := tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -484,14 +479,14 @@ func BenchmarkParallelExecuteComplexWithSandboxActive(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkExecuteComplexWithoutSandbox(b *testing.B) {
|
||||
s := NewSet("set without sandbox")
|
||||
s := pongo2.NewSet("set without sandbox", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
tpl, err := s.FromFile("template_tests/complex.tpl")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -505,7 +500,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
|||
}
|
||||
preloadedTpl := string(buf)
|
||||
|
||||
s := NewSet("set without sandbox")
|
||||
s := pongo2.NewSet("set without sandbox", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -514,7 +509,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
|||
b.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = tpl.ExecuteBytes(tplContext)
|
||||
err = tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -522,7 +517,7 @@ func BenchmarkCompileAndExecuteComplexWithoutSandbox(b *testing.B) {
|
|||
}
|
||||
|
||||
func BenchmarkParallelExecuteComplexWithoutSandbox(b *testing.B) {
|
||||
s := NewSet("set without sandbox")
|
||||
s := pongo2.NewSet("set without sandbox", pongo2.MustNewLocalFileSystemLoader(""))
|
||||
tpl, err := s.FromFile("template_tests/complex.tpl")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
|
@ -530,7 +525,7 @@ func BenchmarkParallelExecuteComplexWithoutSandbox(b *testing.B) {
|
|||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, err := tpl.ExecuteBytes(tplContext)
|
||||
err := tpl.ExecuteWriterUnbuffered(tplContext, ioutil.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
|
67
vendor/github.com/flosch/pongo2/pongo2_test.go
generated
vendored
67
vendor/github.com/flosch/pongo2/pongo2_test.go
generated
vendored
|
@ -1,26 +1,26 @@
|
|||
package pongo2
|
||||
package pongo2_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/flosch/pongo2"
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
// Hook up gocheck into the "go test" runner.
|
||||
|
||||
func Test(t *testing.T) { TestingT(t) }
|
||||
|
||||
type TestSuite struct {
|
||||
tpl *Template
|
||||
tpl *pongo2.Template
|
||||
}
|
||||
|
||||
var (
|
||||
_ = Suite(&TestSuite{})
|
||||
test_suite2 = NewSet("test suite 2")
|
||||
_ = 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)
|
||||
}
|
||||
|
|
41
vendor/github.com/flosch/pongo2/tags.go
generated
vendored
41
vendor/github.com/flosch/pongo2/tags.go
generated
vendored
|
@ -21,6 +21,8 @@ package pongo2
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type INodeTag interface {
|
||||
|
@ -53,80 +55,81 @@ func init() {
|
|||
tags = make(map[string]*tag)
|
||||
}
|
||||
|
||||
// Registers a new tag. If there's already a tag with the same
|
||||
// name, RegisterTag will panic. You usually want to call this
|
||||
// Registers a new tag. You usually want to call this
|
||||
// function in the tag's init() function:
|
||||
// http://golang.org/doc/effective_go.html#init
|
||||
//
|
||||
// See http://www.florian-schlachter.de/post/pongo2/ for more about
|
||||
// writing filters and tags.
|
||||
func RegisterTag(name string, parserFn TagParser) {
|
||||
func RegisterTag(name string, parserFn TagParser) error {
|
||||
_, existing := tags[name]
|
||||
if existing {
|
||||
panic(fmt.Sprintf("Tag with name '%s' is already registered.", name))
|
||||
return errors.Errorf("tag with name '%s' is already registered", name)
|
||||
}
|
||||
tags[name] = &tag{
|
||||
name: name,
|
||||
parser: parserFn,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Replaces an already registered tag with a new implementation. Use this
|
||||
// function with caution since it allows you to change existing tag behaviour.
|
||||
func ReplaceTag(name string, parserFn TagParser) {
|
||||
func ReplaceTag(name string, parserFn TagParser) error {
|
||||
_, existing := tags[name]
|
||||
if !existing {
|
||||
panic(fmt.Sprintf("Tag with name '%s' does not exist (therefore cannot be overridden).", name))
|
||||
return errors.Errorf("tag with name '%s' does not exist (therefore cannot be overridden)", name)
|
||||
}
|
||||
tags[name] = &tag{
|
||||
name: name,
|
||||
parser: parserFn,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tag = "{%" IDENT ARGS "%}"
|
||||
func (p *Parser) parseTagElement() (INodeTag, *Error) {
|
||||
p.Consume() // consume "{%"
|
||||
token_name := p.MatchType(TokenIdentifier)
|
||||
tokenName := p.MatchType(TokenIdentifier)
|
||||
|
||||
// Check for identifier
|
||||
if token_name == nil {
|
||||
if tokenName == nil {
|
||||
return nil, p.Error("Tag name must be an identifier.", nil)
|
||||
}
|
||||
|
||||
// Check for the existing tag
|
||||
tag, exists := tags[token_name.Val]
|
||||
tag, exists := tags[tokenName.Val]
|
||||
if !exists {
|
||||
// Does not exists
|
||||
return nil, p.Error(fmt.Sprintf("Tag '%s' not found (or beginning tag not provided)", token_name.Val), token_name)
|
||||
return nil, p.Error(fmt.Sprintf("Tag '%s' not found (or beginning tag not provided)", tokenName.Val), tokenName)
|
||||
}
|
||||
|
||||
// Check sandbox tag restriction
|
||||
if _, is_banned := p.template.set.bannedTags[token_name.Val]; is_banned {
|
||||
return nil, p.Error(fmt.Sprintf("Usage of tag '%s' is not allowed (sandbox restriction active).", token_name.Val), token_name)
|
||||
if _, isBanned := p.template.set.bannedTags[tokenName.Val]; isBanned {
|
||||
return nil, p.Error(fmt.Sprintf("Usage of tag '%s' is not allowed (sandbox restriction active).", tokenName.Val), tokenName)
|
||||
}
|
||||
|
||||
args_token := make([]*Token, 0)
|
||||
var argsToken []*Token
|
||||
for p.Peek(TokenSymbol, "%}") == nil && p.Remaining() > 0 {
|
||||
// Add token to args
|
||||
args_token = append(args_token, p.Current())
|
||||
argsToken = append(argsToken, p.Current())
|
||||
p.Consume() // next token
|
||||
}
|
||||
|
||||
// EOF?
|
||||
if p.Remaining() == 0 {
|
||||
return nil, p.Error("Unexpectedly reached EOF, no tag end found.", p.last_token)
|
||||
return nil, p.Error("Unexpectedly reached EOF, no tag end found.", p.lastToken)
|
||||
}
|
||||
|
||||
p.Match(TokenSymbol, "%}")
|
||||
|
||||
arg_parser := newParser(p.name, args_token, p.template)
|
||||
if len(args_token) == 0 {
|
||||
argParser := newParser(p.name, argsToken, p.template)
|
||||
if len(argsToken) == 0 {
|
||||
// This is done to have nice EOF error messages
|
||||
arg_parser.last_token = token_name
|
||||
argParser.lastToken = tokenName
|
||||
}
|
||||
|
||||
p.template.level++
|
||||
defer func() { p.template.level-- }()
|
||||
return tag.parser(p, token_name, arg_parser)
|
||||
return tag.parser(p, tokenName, argParser)
|
||||
}
|
||||
|
|
26
vendor/github.com/flosch/pongo2/tags_autoescape.go
generated
vendored
26
vendor/github.com/flosch/pongo2/tags_autoescape.go
generated
vendored
|
@ -1,19 +1,15 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagAutoescapeNode struct {
|
||||
wrapper *NodeWrapper
|
||||
autoescape bool
|
||||
}
|
||||
|
||||
func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
old := ctx.Autoescape
|
||||
ctx.Autoescape = node.autoescape
|
||||
|
||||
err := node.wrapper.Execute(ctx, buffer)
|
||||
err := node.wrapper.Execute(ctx, writer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -24,22 +20,22 @@ func (node *tagAutoescapeNode) Execute(ctx *ExecutionContext, buffer *bytes.Buff
|
|||
}
|
||||
|
||||
func tagAutoescapeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
autoescape_node := &tagAutoescapeNode{}
|
||||
autoescapeNode := &tagAutoescapeNode{}
|
||||
|
||||
wrapper, _, err := doc.WrapUntilTag("endautoescape")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
autoescape_node.wrapper = wrapper
|
||||
autoescapeNode.wrapper = wrapper
|
||||
|
||||
mode_token := arguments.MatchType(TokenIdentifier)
|
||||
if mode_token == nil {
|
||||
modeToken := arguments.MatchType(TokenIdentifier)
|
||||
if modeToken == nil {
|
||||
return nil, arguments.Error("A mode is required for autoescape-tag.", nil)
|
||||
}
|
||||
if mode_token.Val == "on" {
|
||||
autoescape_node.autoescape = true
|
||||
} else if mode_token.Val == "off" {
|
||||
autoescape_node.autoescape = false
|
||||
if modeToken.Val == "on" {
|
||||
autoescapeNode.autoescape = true
|
||||
} else if modeToken.Val == "off" {
|
||||
autoescapeNode.autoescape = false
|
||||
} else {
|
||||
return nil, arguments.Error("Only 'on' or 'off' is valid as an autoescape-mode.", nil)
|
||||
}
|
||||
|
@ -48,7 +44,7 @@ func tagAutoescapeParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
|||
return nil, arguments.Error("Malformed autoescape-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return autoescape_node, nil
|
||||
return autoescapeNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
91
vendor/github.com/flosch/pongo2/tags_block.go
generated
vendored
91
vendor/github.com/flosch/pongo2/tags_block.go
generated
vendored
|
@ -9,47 +9,82 @@ type tagBlockNode struct {
|
|||
name string
|
||||
}
|
||||
|
||||
func (node *tagBlockNode) getBlockWrapperByName(tpl *Template) *NodeWrapper {
|
||||
func (node *tagBlockNode) getBlockWrappers(tpl *Template) []*NodeWrapper {
|
||||
nodeWrappers := make([]*NodeWrapper, 0)
|
||||
var t *NodeWrapper
|
||||
if tpl.child != nil {
|
||||
// First ask the child for the block
|
||||
t = node.getBlockWrapperByName(tpl.child)
|
||||
}
|
||||
if t == nil {
|
||||
// Child has no block, lets look up here at parent
|
||||
|
||||
for tpl != nil {
|
||||
t = tpl.blocks[node.name]
|
||||
if t != nil {
|
||||
nodeWrappers = append(nodeWrappers, t)
|
||||
}
|
||||
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() {
|
||||
|
|
12
vendor/github.com/flosch/pongo2/tags_comment.go
generated
vendored
12
vendor/github.com/flosch/pongo2/tags_comment.go
generated
vendored
|
@ -1,20 +1,16 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagCommentNode struct{}
|
||||
|
||||
func (node *tagCommentNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagCommentNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagCommentParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
comment_node := &tagCommentNode{}
|
||||
commentNode := &tagCommentNode{}
|
||||
|
||||
// TODO: Process the endtag's arguments (see django 'comment'-tag documentation)
|
||||
_, _, err := doc.WrapUntilTag("endcomment")
|
||||
err := doc.SkipUntilTag("endcomment")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -23,7 +19,7 @@ func tagCommentParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
return nil, arguments.Error("Tag 'comment' does not take any argument.", nil)
|
||||
}
|
||||
|
||||
return comment_node, nil
|
||||
return commentNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
34
vendor/github.com/flosch/pongo2/tags_cycle.go
generated
vendored
34
vendor/github.com/flosch/pongo2/tags_cycle.go
generated
vendored
|
@ -1,9 +1,5 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagCycleValue struct {
|
||||
node *tagCycleNode
|
||||
value *Value
|
||||
|
@ -13,7 +9,7 @@ type tagCycleNode struct {
|
|||
position *Token
|
||||
args []IEvaluator
|
||||
idx int
|
||||
as_name string
|
||||
asName string
|
||||
silent bool
|
||||
}
|
||||
|
||||
|
@ -21,7 +17,7 @@ func (cv *tagCycleValue) String() string {
|
|||
return cv.value.String()
|
||||
}
|
||||
|
||||
func (node *tagCycleNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagCycleNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
item := node.args[node.idx%len(node.args)]
|
||||
node.idx++
|
||||
|
||||
|
@ -46,30 +42,30 @@ func (node *tagCycleNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *
|
|||
t.value = val
|
||||
|
||||
if !t.node.silent {
|
||||
buffer.WriteString(val.String())
|
||||
writer.WriteString(val.String())
|
||||
}
|
||||
} else {
|
||||
// Regular call
|
||||
|
||||
cycle_value := &tagCycleValue{
|
||||
cycleValue := &tagCycleValue{
|
||||
node: node,
|
||||
value: val,
|
||||
}
|
||||
|
||||
if node.as_name != "" {
|
||||
ctx.Private[node.as_name] = cycle_value
|
||||
if node.asName != "" {
|
||||
ctx.Private[node.asName] = cycleValue
|
||||
}
|
||||
if !node.silent {
|
||||
buffer.WriteString(val.String())
|
||||
writer.WriteString(val.String())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HINT: We're not supporting the old comma-seperated list of expresions argument-style
|
||||
// HINT: We're not supporting the old comma-separated list of expressions argument-style
|
||||
func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
cycle_node := &tagCycleNode{
|
||||
cycleNode := &tagCycleNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
|
@ -78,19 +74,19 @@ func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cycle_node.args = append(cycle_node.args, node)
|
||||
cycleNode.args = append(cycleNode.args, node)
|
||||
|
||||
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
||||
// as
|
||||
|
||||
name_token := arguments.MatchType(TokenIdentifier)
|
||||
if name_token == nil {
|
||||
nameToken := arguments.MatchType(TokenIdentifier)
|
||||
if nameToken == nil {
|
||||
return nil, arguments.Error("Name (identifier) expected after 'as'.", nil)
|
||||
}
|
||||
cycle_node.as_name = name_token.Val
|
||||
cycleNode.asName = nameToken.Val
|
||||
|
||||
if arguments.MatchOne(TokenIdentifier, "silent") != nil {
|
||||
cycle_node.silent = true
|
||||
cycleNode.silent = true
|
||||
}
|
||||
|
||||
// Now we're finished
|
||||
|
@ -102,7 +98,7 @@ func tagCycleParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Er
|
|||
return nil, arguments.Error("Malformed cycle-tag.", nil)
|
||||
}
|
||||
|
||||
return cycle_node, nil
|
||||
return cycleNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
22
vendor/github.com/flosch/pongo2/tags_extends.go
generated
vendored
22
vendor/github.com/flosch/pongo2/tags_extends.go
generated
vendored
|
@ -1,19 +1,15 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagExtendsNode struct {
|
||||
filename string
|
||||
}
|
||||
|
||||
func (node *tagExtendsNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagExtendsNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
extends_node := &tagExtendsNode{}
|
||||
extendsNode := &tagExtendsNode{}
|
||||
|
||||
if doc.template.level > 1 {
|
||||
return nil, arguments.Error("The 'extends' tag can only defined on root level.", start)
|
||||
|
@ -24,22 +20,22 @@ func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
return nil, arguments.Error("This template has already one parent.", start)
|
||||
}
|
||||
|
||||
if filename_token := arguments.MatchType(TokenString); filename_token != nil {
|
||||
if filenameToken := arguments.MatchType(TokenString); filenameToken != nil {
|
||||
// prepared, static template
|
||||
|
||||
// Get parent's filename
|
||||
parent_filename := doc.template.set.resolveFilename(doc.template, filename_token.Val)
|
||||
parentFilename := doc.template.set.resolveFilename(doc.template, filenameToken.Val)
|
||||
|
||||
// Parse the parent
|
||||
parent_template, err := doc.template.set.FromFile(parent_filename)
|
||||
parentTemplate, err := doc.template.set.FromFile(parentFilename)
|
||||
if err != nil {
|
||||
return nil, err.(*Error)
|
||||
}
|
||||
|
||||
// Keep track of things
|
||||
parent_template.child = doc.template
|
||||
doc.template.parent = parent_template
|
||||
extends_node.filename = parent_filename
|
||||
parentTemplate.child = doc.template
|
||||
doc.template.parent = parentTemplate
|
||||
extendsNode.filename = parentFilename
|
||||
} else {
|
||||
return nil, arguments.Error("Tag 'extends' requires a template filename as string.", nil)
|
||||
}
|
||||
|
@ -48,7 +44,7 @@ func tagExtendsParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
return nil, arguments.Error("Tag 'extends' does only take 1 argument.", nil)
|
||||
}
|
||||
|
||||
return extends_node, nil
|
||||
return extendsNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
28
vendor/github.com/flosch/pongo2/tags_filter.go
generated
vendored
28
vendor/github.com/flosch/pongo2/tags_filter.go
generated
vendored
|
@ -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() {
|
||||
|
|
14
vendor/github.com/flosch/pongo2/tags_firstof.go
generated
vendored
14
vendor/github.com/flosch/pongo2/tags_firstof.go
generated
vendored
|
@ -1,15 +1,11 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagFirstofNode struct {
|
||||
position *Token
|
||||
args []IEvaluator
|
||||
}
|
||||
|
||||
func (node *tagFirstofNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagFirstofNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
for _, arg := range node.args {
|
||||
val, err := arg.Evaluate(ctx)
|
||||
if err != nil {
|
||||
|
@ -24,7 +20,7 @@ func (node *tagFirstofNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
}
|
||||
}
|
||||
|
||||
buffer.WriteString(val.String())
|
||||
writer.WriteString(val.String())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +29,7 @@ func (node *tagFirstofNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
}
|
||||
|
||||
func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
firstof_node := &tagFirstofNode{
|
||||
firstofNode := &tagFirstofNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
|
@ -42,10 +38,10 @@ func tagFirstofParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
firstof_node.args = append(firstof_node.args, node)
|
||||
firstofNode.args = append(firstofNode.args, node)
|
||||
}
|
||||
|
||||
return firstof_node, nil
|
||||
return firstofNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
59
vendor/github.com/flosch/pongo2/tags_for.go
generated
vendored
59
vendor/github.com/flosch/pongo2/tags_for.go
generated
vendored
|
@ -1,14 +1,11 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagForNode struct {
|
||||
key string
|
||||
value string // only for maps: for key, value in map
|
||||
object_evaluator IEvaluator
|
||||
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() {
|
||||
|
|
39
vendor/github.com/flosch/pongo2/tags_if.go
generated
vendored
39
vendor/github.com/flosch/pongo2/tags_if.go
generated
vendored
|
@ -1,15 +1,11 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIfNode struct {
|
||||
conditions []IEvaluator
|
||||
wrappers []*NodeWrapper
|
||||
}
|
||||
|
||||
func (node *tagIfNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagIfNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
for i, condition := range node.conditions {
|
||||
result, err := condition.Evaluate(ctx)
|
||||
if err != nil {
|
||||
|
@ -17,26 +13,25 @@ func (node *tagIfNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Err
|
|||
}
|
||||
|
||||
if result.IsTrue() {
|
||||
return node.wrappers[i].Execute(ctx, buffer)
|
||||
} else {
|
||||
// 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() {
|
||||
|
|
51
vendor/github.com/flosch/pongo2/tags_ifchanged.go
generated
vendored
51
vendor/github.com/flosch/pongo2/tags_ifchanged.go
generated
vendored
|
@ -5,16 +5,15 @@ import (
|
|||
)
|
||||
|
||||
type tagIfchangedNode struct {
|
||||
watched_expr []IEvaluator
|
||||
last_values []*Value
|
||||
last_content []byte
|
||||
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() {
|
||||
|
|
27
vendor/github.com/flosch/pongo2/tags_ifequal.go
generated
vendored
27
vendor/github.com/flosch/pongo2/tags_ifequal.go
generated
vendored
|
@ -1,16 +1,12 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIfEqualNode struct {
|
||||
var1, var2 IEvaluator
|
||||
thenWrapper *NodeWrapper
|
||||
elseWrapper *NodeWrapper
|
||||
}
|
||||
|
||||
func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
r1, err := node.var1.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -23,17 +19,16 @@ func (node *tagIfEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
result := r1.EqualValueTo(r2)
|
||||
|
||||
if result {
|
||||
return node.thenWrapper.Execute(ctx, buffer)
|
||||
} else {
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, buffer)
|
||||
}
|
||||
return node.thenWrapper.Execute(ctx, writer)
|
||||
}
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, writer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
ifequal_node := &tagIfEqualNode{}
|
||||
ifequalNode := &tagIfEqualNode{}
|
||||
|
||||
// Parse two expressions
|
||||
var1, err := arguments.ParseExpression()
|
||||
|
@ -44,8 +39,8 @@ func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifequal_node.var1 = var1
|
||||
ifequal_node.var2 = var2
|
||||
ifequalNode.var1 = var1
|
||||
ifequalNode.var2 = var2
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
|
||||
|
@ -56,7 +51,7 @@ func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifequal_node.thenWrapper = wrapper
|
||||
ifequalNode.thenWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
|
@ -68,14 +63,14 @@ func tagIfEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifequal_node.elseWrapper = wrapper
|
||||
ifequalNode.elseWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return ifequal_node, nil
|
||||
return ifequalNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
31
vendor/github.com/flosch/pongo2/tags_ifnotequal.go
generated
vendored
31
vendor/github.com/flosch/pongo2/tags_ifnotequal.go
generated
vendored
|
@ -1,16 +1,12 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIfNotEqualNode struct {
|
||||
var1, var2 IEvaluator
|
||||
thenWrapper *NodeWrapper
|
||||
elseWrapper *NodeWrapper
|
||||
}
|
||||
|
||||
func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
r1, err := node.var1.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -23,17 +19,16 @@ func (node *tagIfNotEqualNode) Execute(ctx *ExecutionContext, buffer *bytes.Buff
|
|||
result := !r1.EqualValueTo(r2)
|
||||
|
||||
if result {
|
||||
return node.thenWrapper.Execute(ctx, buffer)
|
||||
} else {
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, buffer)
|
||||
}
|
||||
return node.thenWrapper.Execute(ctx, writer)
|
||||
}
|
||||
if node.elseWrapper != nil {
|
||||
return node.elseWrapper.Execute(ctx, writer)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
ifnotequal_node := &tagIfNotEqualNode{}
|
||||
ifnotequalNode := &tagIfNotEqualNode{}
|
||||
|
||||
// Parse two expressions
|
||||
var1, err := arguments.ParseExpression()
|
||||
|
@ -44,19 +39,19 @@ func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifnotequal_node.var1 = var1
|
||||
ifnotequal_node.var2 = var2
|
||||
ifnotequalNode.var1 = var1
|
||||
ifnotequalNode.var2 = var2
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("ifequal only takes 2 arguments.", nil)
|
||||
}
|
||||
|
||||
// Wrap then/else-blocks
|
||||
wrapper, endargs, err := doc.WrapUntilTag("else", "endifequal")
|
||||
wrapper, endargs, err := doc.WrapUntilTag("else", "endifnotequal")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifnotequal_node.thenWrapper = wrapper
|
||||
ifnotequalNode.thenWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
|
@ -64,18 +59,18 @@ func tagIfNotEqualParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
|||
|
||||
if wrapper.Endtag == "else" {
|
||||
// if there's an else in the if-statement, we need the else-Block as well
|
||||
wrapper, endargs, err = doc.WrapUntilTag("endifequal")
|
||||
wrapper, endargs, err = doc.WrapUntilTag("endifnotequal")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ifnotequal_node.elseWrapper = wrapper
|
||||
ifnotequalNode.elseWrapper = wrapper
|
||||
|
||||
if endargs.Count() > 0 {
|
||||
return nil, endargs.Error("Arguments not allowed here.", nil)
|
||||
}
|
||||
}
|
||||
|
||||
return ifnotequal_node, nil
|
||||
return ifnotequalNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
36
vendor/github.com/flosch/pongo2/tags_import.go
generated
vendored
36
vendor/github.com/flosch/pongo2/tags_import.go
generated
vendored
|
@ -1,18 +1,16 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type tagImportNode struct {
|
||||
position *Token
|
||||
filename string
|
||||
template *Template
|
||||
macros map[string]*tagMacroNode // alias/name -> macro instance
|
||||
}
|
||||
|
||||
func (node *tagImportNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagImportNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
for name, macro := range node.macros {
|
||||
func(name string, macro *tagMacroNode) {
|
||||
ctx.Private[name] = func(args ...*Value) *Value {
|
||||
|
@ -24,50 +22,50 @@ func (node *tagImportNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer)
|
|||
}
|
||||
|
||||
func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
import_node := &tagImportNode{
|
||||
importNode := &tagImportNode{
|
||||
position: start,
|
||||
macros: make(map[string]*tagMacroNode),
|
||||
}
|
||||
|
||||
filename_token := arguments.MatchType(TokenString)
|
||||
if filename_token == nil {
|
||||
filenameToken := arguments.MatchType(TokenString)
|
||||
if filenameToken == nil {
|
||||
return nil, arguments.Error("Import-tag needs a filename as string.", nil)
|
||||
}
|
||||
|
||||
import_node.filename = doc.template.set.resolveFilename(doc.template, filename_token.Val)
|
||||
importNode.filename = doc.template.set.resolveFilename(doc.template, filenameToken.Val)
|
||||
|
||||
if arguments.Remaining() == 0 {
|
||||
return nil, arguments.Error("You must at least specify one macro to import.", nil)
|
||||
}
|
||||
|
||||
// Compile the given template
|
||||
tpl, err := doc.template.set.FromFile(import_node.filename)
|
||||
tpl, err := doc.template.set.FromFile(importNode.filename)
|
||||
if err != nil {
|
||||
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, start)
|
||||
}
|
||||
|
||||
for arguments.Remaining() > 0 {
|
||||
macro_name_token := arguments.MatchType(TokenIdentifier)
|
||||
if macro_name_token == nil {
|
||||
macroNameToken := arguments.MatchType(TokenIdentifier)
|
||||
if macroNameToken == nil {
|
||||
return nil, arguments.Error("Expected macro name (identifier).", nil)
|
||||
}
|
||||
|
||||
as_name := macro_name_token.Val
|
||||
asName := macroNameToken.Val
|
||||
if arguments.Match(TokenKeyword, "as") != nil {
|
||||
alias_token := arguments.MatchType(TokenIdentifier)
|
||||
if alias_token == nil {
|
||||
aliasToken := arguments.MatchType(TokenIdentifier)
|
||||
if aliasToken == nil {
|
||||
return nil, arguments.Error("Expected macro alias name (identifier).", nil)
|
||||
}
|
||||
as_name = alias_token.Val
|
||||
asName = aliasToken.Val
|
||||
}
|
||||
|
||||
macro_instance, has := tpl.exported_macros[macro_name_token.Val]
|
||||
macroInstance, has := tpl.exportedMacros[macroNameToken.Val]
|
||||
if !has {
|
||||
return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macro_name_token.Val,
|
||||
import_node.filename), macro_name_token)
|
||||
return nil, arguments.Error(fmt.Sprintf("Macro '%s' not found (or not exported) in '%s'.", macroNameToken.Val,
|
||||
importNode.filename), macroNameToken)
|
||||
}
|
||||
|
||||
import_node.macros[as_name] = macro_instance
|
||||
importNode.macros[asName] = macroInstance
|
||||
|
||||
if arguments.Remaining() == 0 {
|
||||
break
|
||||
|
@ -78,7 +76,7 @@ func tagImportParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *E
|
|||
}
|
||||
}
|
||||
|
||||
return import_node, nil
|
||||
return importNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
106
vendor/github.com/flosch/pongo2/tags_include.go
generated
vendored
106
vendor/github.com/flosch/pongo2/tags_include.go
generated
vendored
|
@ -1,41 +1,38 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagIncludeNode struct {
|
||||
tpl *Template
|
||||
filename_evaluator IEvaluator
|
||||
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() {
|
||||
|
|
55
vendor/github.com/flosch/pongo2/tags_lorem.go
generated
vendored
55
vendor/github.com/flosch/pongo2/tags_lorem.go
generated
vendored
|
@ -1,10 +1,11 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -19,102 +20,102 @@ type tagLoremNode struct {
|
|||
random bool // does not use the default paragraph "Lorem ipsum dolor sit amet, ..."
|
||||
}
|
||||
|
||||
func (node *tagLoremNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagLoremNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
switch node.method {
|
||||
case "b":
|
||||
if node.random {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
||||
buffer.WriteString(par)
|
||||
writer.WriteString(par)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
||||
buffer.WriteString(par)
|
||||
writer.WriteString(par)
|
||||
}
|
||||
}
|
||||
case "w":
|
||||
if node.random {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString(" ")
|
||||
writer.WriteString(" ")
|
||||
}
|
||||
word := tagLoremWords[rand.Intn(len(tagLoremWords))]
|
||||
buffer.WriteString(word)
|
||||
writer.WriteString(word)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString(" ")
|
||||
writer.WriteString(" ")
|
||||
}
|
||||
word := tagLoremWords[i%len(tagLoremWords)]
|
||||
buffer.WriteString(word)
|
||||
writer.WriteString(word)
|
||||
}
|
||||
}
|
||||
case "p":
|
||||
if node.random {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
buffer.WriteString("<p>")
|
||||
writer.WriteString("<p>")
|
||||
par := tagLoremParagraphs[rand.Intn(len(tagLoremParagraphs))]
|
||||
buffer.WriteString(par)
|
||||
buffer.WriteString("</p>")
|
||||
writer.WriteString(par)
|
||||
writer.WriteString("</p>")
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < node.count; i++ {
|
||||
if i > 0 {
|
||||
buffer.WriteString("\n")
|
||||
writer.WriteString("\n")
|
||||
}
|
||||
buffer.WriteString("<p>")
|
||||
writer.WriteString("<p>")
|
||||
par := tagLoremParagraphs[i%len(tagLoremParagraphs)]
|
||||
buffer.WriteString(par)
|
||||
buffer.WriteString("</p>")
|
||||
writer.WriteString(par)
|
||||
writer.WriteString("</p>")
|
||||
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("unsupported method")
|
||||
return ctx.OrigError(errors.Errorf("unsupported method: %s", node.method), nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagLoremParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
lorem_node := &tagLoremNode{
|
||||
loremNode := &tagLoremNode{
|
||||
position: start,
|
||||
count: 1,
|
||||
method: "b",
|
||||
}
|
||||
|
||||
if count_token := arguments.MatchType(TokenNumber); count_token != nil {
|
||||
lorem_node.count = AsValue(count_token.Val).Integer()
|
||||
if countToken := arguments.MatchType(TokenNumber); countToken != nil {
|
||||
loremNode.count = AsValue(countToken.Val).Integer()
|
||||
}
|
||||
|
||||
if method_token := arguments.MatchType(TokenIdentifier); method_token != nil {
|
||||
if method_token.Val != "w" && method_token.Val != "p" && method_token.Val != "b" {
|
||||
if methodToken := arguments.MatchType(TokenIdentifier); methodToken != nil {
|
||||
if methodToken.Val != "w" && methodToken.Val != "p" && methodToken.Val != "b" {
|
||||
return nil, arguments.Error("lorem-method must be either 'w', 'p' or 'b'.", nil)
|
||||
}
|
||||
|
||||
lorem_node.method = method_token.Val
|
||||
loremNode.method = methodToken.Val
|
||||
}
|
||||
|
||||
if arguments.MatchOne(TokenIdentifier, "random") != nil {
|
||||
lorem_node.random = true
|
||||
loremNode.random = true
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed lorem-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return lorem_node, nil
|
||||
return loremNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
64
vendor/github.com/flosch/pongo2/tags_macro.go
generated
vendored
64
vendor/github.com/flosch/pongo2/tags_macro.go
generated
vendored
|
@ -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() {
|
||||
|
|
17
vendor/github.com/flosch/pongo2/tags_now.go
generated
vendored
17
vendor/github.com/flosch/pongo2/tags_now.go
generated
vendored
|
@ -1,7 +1,6 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -11,7 +10,7 @@ type tagNowNode struct {
|
|||
fake bool
|
||||
}
|
||||
|
||||
func (node *tagNowNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagNowNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
var t time.Time
|
||||
if node.fake {
|
||||
t = time.Date(2014, time.February, 05, 18, 31, 45, 00, time.UTC)
|
||||
|
@ -19,31 +18,31 @@ func (node *tagNowNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Er
|
|||
t = time.Now()
|
||||
}
|
||||
|
||||
buffer.WriteString(t.Format(node.format))
|
||||
writer.WriteString(t.Format(node.format))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagNowParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
now_node := &tagNowNode{
|
||||
nowNode := &tagNowNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
format_token := arguments.MatchType(TokenString)
|
||||
if format_token == nil {
|
||||
formatToken := arguments.MatchType(TokenString)
|
||||
if formatToken == nil {
|
||||
return nil, arguments.Error("Expected a format string.", nil)
|
||||
}
|
||||
now_node.format = format_token.Val
|
||||
nowNode.format = formatToken.Val
|
||||
|
||||
if arguments.MatchOne(TokenIdentifier, "fake") != nil {
|
||||
now_node.fake = true
|
||||
nowNode.fake = true
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed now-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return now_node, nil
|
||||
return nowNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
4
vendor/github.com/flosch/pongo2/tags_set.go
generated
vendored
4
vendor/github.com/flosch/pongo2/tags_set.go
generated
vendored
|
@ -1,13 +1,11 @@
|
|||
package pongo2
|
||||
|
||||
import "bytes"
|
||||
|
||||
type tagSetNode struct {
|
||||
name string
|
||||
expression IEvaluator
|
||||
}
|
||||
|
||||
func (node *tagSetNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagSetNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
// Evaluate expression
|
||||
value, err := node.expression.Evaluate(ctx)
|
||||
if err != nil {
|
||||
|
|
10
vendor/github.com/flosch/pongo2/tags_spaceless.go
generated
vendored
10
vendor/github.com/flosch/pongo2/tags_spaceless.go
generated
vendored
|
@ -11,7 +11,7 @@ type tagSpacelessNode struct {
|
|||
|
||||
var tagSpacelessRegexp = regexp.MustCompile(`(?U:(<.*>))([\t\n\v\f\r ]+)(?U:(<.*>))`)
|
||||
|
||||
func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
b := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
|
||||
|
||||
err := node.wrapper.Execute(ctx, b)
|
||||
|
@ -28,25 +28,25 @@ func (node *tagSpacelessNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffe
|
|||
s = s2
|
||||
}
|
||||
|
||||
buffer.WriteString(s)
|
||||
writer.WriteString(s)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagSpacelessParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
spaceless_node := &tagSpacelessNode{}
|
||||
spacelessNode := &tagSpacelessNode{}
|
||||
|
||||
wrapper, _, err := doc.WrapUntilTag("endspaceless")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spaceless_node.wrapper = wrapper
|
||||
spacelessNode.wrapper = wrapper
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed spaceless-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return spaceless_node, nil
|
||||
return spacelessNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
31
vendor/github.com/flosch/pongo2/tags_ssi.go
generated
vendored
31
vendor/github.com/flosch/pongo2/tags_ssi.go
generated
vendored
|
@ -1,7 +1,6 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
|
@ -11,47 +10,47 @@ type tagSSINode struct {
|
|||
template *Template
|
||||
}
|
||||
|
||||
func (node *tagSSINode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagSSINode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
if node.template != nil {
|
||||
// Execute the template within the current context
|
||||
includeCtx := make(Context)
|
||||
includeCtx.Update(ctx.Public)
|
||||
includeCtx.Update(ctx.Private)
|
||||
|
||||
err := node.template.ExecuteWriter(includeCtx, buffer)
|
||||
err := node.template.execute(includeCtx, writer)
|
||||
if err != nil {
|
||||
return err.(*Error)
|
||||
}
|
||||
} else {
|
||||
// Just print out the content
|
||||
buffer.WriteString(node.content)
|
||||
writer.WriteString(node.content)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagSSIParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
ssi_node := &tagSSINode{}
|
||||
SSINode := &tagSSINode{}
|
||||
|
||||
if file_token := arguments.MatchType(TokenString); file_token != nil {
|
||||
ssi_node.filename = file_token.Val
|
||||
if fileToken := arguments.MatchType(TokenString); fileToken != nil {
|
||||
SSINode.filename = fileToken.Val
|
||||
|
||||
if arguments.Match(TokenIdentifier, "parsed") != nil {
|
||||
// parsed
|
||||
temporary_tpl, err := doc.template.set.FromFile(doc.template.set.resolveFilename(doc.template, file_token.Val))
|
||||
temporaryTpl, err := doc.template.set.FromFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
|
||||
if err != nil {
|
||||
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, file_token)
|
||||
return nil, err.(*Error).updateFromTokenIfNeeded(doc.template, fileToken)
|
||||
}
|
||||
ssi_node.template = temporary_tpl
|
||||
SSINode.template = temporaryTpl
|
||||
} else {
|
||||
// plaintext
|
||||
buf, err := ioutil.ReadFile(doc.template.set.resolveFilename(doc.template, file_token.Val))
|
||||
buf, err := ioutil.ReadFile(doc.template.set.resolveFilename(doc.template, fileToken.Val))
|
||||
if err != nil {
|
||||
return nil, (&Error{
|
||||
Sender: "tag:ssi",
|
||||
ErrorMsg: err.Error(),
|
||||
}).updateFromTokenIfNeeded(doc.template, file_token)
|
||||
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() {
|
||||
|
|
20
vendor/github.com/flosch/pongo2/tags_templatetag.go
generated
vendored
20
vendor/github.com/flosch/pongo2/tags_templatetag.go
generated
vendored
|
@ -1,9 +1,5 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagTemplateTagNode struct {
|
||||
content string
|
||||
}
|
||||
|
@ -19,20 +15,20 @@ var templateTagMapping = map[string]string{
|
|||
"closecomment": "#}",
|
||||
}
|
||||
|
||||
func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
buffer.WriteString(node.content)
|
||||
func (node *tagTemplateTagNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
writer.WriteString(node.content)
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
tt_node := &tagTemplateTagNode{}
|
||||
ttNode := &tagTemplateTagNode{}
|
||||
|
||||
if arg_token := arguments.MatchType(TokenIdentifier); arg_token != nil {
|
||||
output, found := templateTagMapping[arg_token.Val]
|
||||
if argToken := arguments.MatchType(TokenIdentifier); argToken != nil {
|
||||
output, found := templateTagMapping[argToken.Val]
|
||||
if !found {
|
||||
return nil, arguments.Error("Argument not found", arg_token)
|
||||
return nil, arguments.Error("Argument not found", argToken)
|
||||
}
|
||||
tt_node.content = output
|
||||
ttNode.content = output
|
||||
} else {
|
||||
return nil, arguments.Error("Identifier expected.", nil)
|
||||
}
|
||||
|
@ -41,7 +37,7 @@ func tagTemplateTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTa
|
|||
return nil, arguments.Error("Malformed templatetag-tag argument.", nil)
|
||||
}
|
||||
|
||||
return tt_node, nil
|
||||
return ttNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
27
vendor/github.com/flosch/pongo2/tags_widthratio.go
generated
vendored
27
vendor/github.com/flosch/pongo2/tags_widthratio.go
generated
vendored
|
@ -1,7 +1,6 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
@ -10,10 +9,10 @@ type tagWidthratioNode struct {
|
|||
position *Token
|
||||
current, max IEvaluator
|
||||
width IEvaluator
|
||||
ctx_name string
|
||||
ctxName string
|
||||
}
|
||||
|
||||
func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
|
||||
func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, writer TemplateWriter) *Error {
|
||||
current, err := node.current.Evaluate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -31,17 +30,17 @@ func (node *tagWidthratioNode) Execute(ctx *ExecutionContext, buffer *bytes.Buff
|
|||
|
||||
value := int(math.Ceil(current.Float()/max.Float()*width.Float() + 0.5))
|
||||
|
||||
if node.ctx_name == "" {
|
||||
buffer.WriteString(fmt.Sprintf("%d", value))
|
||||
if node.ctxName == "" {
|
||||
writer.WriteString(fmt.Sprintf("%d", value))
|
||||
} else {
|
||||
ctx.Private[node.ctx_name] = value
|
||||
ctx.Private[node.ctxName] = value
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, *Error) {
|
||||
widthratio_node := &tagWidthratioNode{
|
||||
widthratioNode := &tagWidthratioNode{
|
||||
position: start,
|
||||
}
|
||||
|
||||
|
@ -49,34 +48,34 @@ func tagWidthratioParser(doc *Parser, start *Token, arguments *Parser) (INodeTag
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
widthratio_node.current = current
|
||||
widthratioNode.current = current
|
||||
|
||||
max, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
widthratio_node.max = max
|
||||
widthratioNode.max = max
|
||||
|
||||
width, err := arguments.ParseExpression()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
widthratio_node.width = width
|
||||
widthratioNode.width = width
|
||||
|
||||
if arguments.MatchOne(TokenKeyword, "as") != nil {
|
||||
// Name follows
|
||||
name_token := arguments.MatchType(TokenIdentifier)
|
||||
if name_token == nil {
|
||||
nameToken := arguments.MatchType(TokenIdentifier)
|
||||
if nameToken == nil {
|
||||
return nil, arguments.Error("Expected name (identifier).", nil)
|
||||
}
|
||||
widthratio_node.ctx_name = name_token.Val
|
||||
widthratioNode.ctxName = nameToken.Val
|
||||
}
|
||||
|
||||
if arguments.Remaining() > 0 {
|
||||
return nil, arguments.Error("Malformed widthratio-tag arguments.", nil)
|
||||
}
|
||||
|
||||
return widthratio_node, nil
|
||||
return widthratioNode, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
44
vendor/github.com/flosch/pongo2/tags_with.go
generated
vendored
44
vendor/github.com/flosch/pongo2/tags_with.go
generated
vendored
|
@ -1,20 +1,16 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type tagWithNode struct {
|
||||
with_pairs map[string]IEvaluator
|
||||
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() {
|
||||
|
|
128
vendor/github.com/flosch/pongo2/template.go
generated
vendored
128
vendor/github.com/flosch/pongo2/template.go
generated
vendored
|
@ -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, "<string>", true, tpl)
|
||||
}
|
||||
|
||||
func newTemplate(set *TemplateSet, name string, is_tpl_string bool, tpl string) (*Template, error) {
|
||||
func newTemplate(set *TemplateSet, name string, isTplString bool, tpl []byte) (*Template, error) {
|
||||
strTpl := string(tpl)
|
||||
|
||||
// Create the template
|
||||
t := &Template{
|
||||
set: set,
|
||||
is_tpl_string: is_tpl_string,
|
||||
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
|
||||
}
|
||||
|
|
157
vendor/github.com/flosch/pongo2/template_loader.go
generated
vendored
Normal file
157
vendor/github.com/flosch/pongo2/template_loader.go
generated
vendored
Normal file
|
@ -0,0 +1,157 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// LocalFilesystemLoader represents a local filesystem loader with basic
|
||||
// BaseDirectory capabilities. The access to the local filesystem is unrestricted.
|
||||
type LocalFilesystemLoader struct {
|
||||
baseDir string
|
||||
}
|
||||
|
||||
// MustNewLocalFileSystemLoader creates a new LocalFilesystemLoader instance
|
||||
// and panics if there's any error during instantiation. The parameters
|
||||
// are the same like NewLocalFileSystemLoader.
|
||||
func MustNewLocalFileSystemLoader(baseDir string) *LocalFilesystemLoader {
|
||||
fs, err := NewLocalFileSystemLoader(baseDir)
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
return fs
|
||||
}
|
||||
|
||||
// NewLocalFileSystemLoader creates a new LocalFilesystemLoader and allows
|
||||
// templatesto be loaded from disk (unrestricted). If any base directory
|
||||
// is given (or being set using SetBaseDir), this base directory is being used
|
||||
// for path calculation in template inclusions/imports. Otherwise the path
|
||||
// is calculated based relatively to the including template's path.
|
||||
func NewLocalFileSystemLoader(baseDir string) (*LocalFilesystemLoader, error) {
|
||||
fs := &LocalFilesystemLoader{}
|
||||
if baseDir != "" {
|
||||
if err := fs.SetBaseDir(baseDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return fs, nil
|
||||
}
|
||||
|
||||
// SetBaseDir sets the template's base directory. This directory will
|
||||
// be used for any relative path in filters, tags and From*-functions to determine
|
||||
// your template. See the comment for NewLocalFileSystemLoader as well.
|
||||
func (fs *LocalFilesystemLoader) SetBaseDir(path string) error {
|
||||
// Make the path absolute
|
||||
if !filepath.IsAbs(path) {
|
||||
abs, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path = abs
|
||||
}
|
||||
|
||||
// Check for existence
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !fi.IsDir() {
|
||||
return errors.Errorf("The given path '%s' is not a directory.", path)
|
||||
}
|
||||
|
||||
fs.baseDir = path
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get reads the path's content from your local filesystem.
|
||||
func (fs *LocalFilesystemLoader) Get(path string) (io.Reader, error) {
|
||||
buf, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.NewReader(buf), nil
|
||||
}
|
||||
|
||||
// Abs resolves a filename relative to the base directory. Absolute paths are allowed.
|
||||
// When there's no base dir set, the absolute path to the filename
|
||||
// will be calculated based on either the provided base directory (which
|
||||
// might be a path of a template which includes another template) or
|
||||
// the current working directory.
|
||||
func (fs *LocalFilesystemLoader) Abs(base, name string) string {
|
||||
if filepath.IsAbs(name) {
|
||||
return name
|
||||
}
|
||||
|
||||
// Our own base dir has always priority; if there's none
|
||||
// we use the path provided in base.
|
||||
var err error
|
||||
if fs.baseDir == "" {
|
||||
if base == "" {
|
||||
base, err = os.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return filepath.Join(base, name)
|
||||
}
|
||||
|
||||
return filepath.Join(filepath.Dir(base), name)
|
||||
}
|
||||
|
||||
return filepath.Join(fs.baseDir, name)
|
||||
}
|
||||
|
||||
// SandboxedFilesystemLoader is still WIP.
|
||||
type SandboxedFilesystemLoader struct {
|
||||
*LocalFilesystemLoader
|
||||
}
|
||||
|
||||
// NewSandboxedFilesystemLoader creates a new sandboxed local file system instance.
|
||||
func NewSandboxedFilesystemLoader(baseDir string) (*SandboxedFilesystemLoader, error) {
|
||||
fs, err := NewLocalFileSystemLoader(baseDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SandboxedFilesystemLoader{
|
||||
LocalFilesystemLoader: fs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Move sandbox to a virtual fs
|
||||
|
||||
/*
|
||||
if len(set.SandboxDirectories) > 0 {
|
||||
defer func() {
|
||||
// Remove any ".." or other crap
|
||||
resolvedPath = filepath.Clean(resolvedPath)
|
||||
|
||||
// Make the path absolute
|
||||
absPath, err := filepath.Abs(resolvedPath)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resolvedPath = absPath
|
||||
|
||||
// Check against the sandbox directories (once one pattern matches, we're done and can allow it)
|
||||
for _, pattern := range set.SandboxDirectories {
|
||||
matched, err := filepath.Match(pattern, resolvedPath)
|
||||
if err != nil {
|
||||
panic("Wrong sandbox directory match pattern (see http://golang.org/pkg/path/filepath/#Match).")
|
||||
}
|
||||
if matched {
|
||||
// OK!
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// No pattern matched, we have to log+deny the request
|
||||
set.logf("Access attempt outside of the sandbox directories (blocked): '%s'", resolvedPath)
|
||||
resolvedPath = ""
|
||||
}()
|
||||
}
|
||||
*/
|
276
vendor/github.com/flosch/pongo2/template_sets.go
generated
vendored
276
vendor/github.com/flosch/pongo2/template_sets.go
generated
vendored
|
@ -2,48 +2,49 @@ package pongo2
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
// A template set allows you to create your own group of templates with their own global context (which is shared
|
||||
// among all members of the set), their own configuration (like a specific base directory) and their own sandbox.
|
||||
// It's useful for a separation of different kind of templates (e. g. web templates vs. mail templates).
|
||||
// TemplateLoader allows to implement a virtual file system.
|
||||
type TemplateLoader interface {
|
||||
// Abs calculates the path to a given template. Whenever a path must be resolved
|
||||
// due to an import from another template, the base equals the parent template's path.
|
||||
Abs(base, name string) string
|
||||
|
||||
// Get returns an io.Reader where the template's content can be read from.
|
||||
Get(path string) (io.Reader, error)
|
||||
}
|
||||
|
||||
// TemplateSet allows you to create your own group of templates with their own
|
||||
// global context (which is shared among all members of the set) and their own
|
||||
// configuration.
|
||||
// It's useful for a separation of different kind of templates
|
||||
// (e. g. web templates vs. mail templates).
|
||||
type TemplateSet struct {
|
||||
name string
|
||||
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
|
||||
|
|
183
vendor/github.com/flosch/pongo2/value.go
generated
vendored
183
vendor/github.com/flosch/pongo2/value.go
generated
vendored
|
@ -3,6 +3,7 @@ package pongo2
|
|||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
@ -12,7 +13,7 @@ type Value struct {
|
|||
safe bool // used to indicate whether a Value needs explicit escaping in the template
|
||||
}
|
||||
|
||||
// Converts any given value to a pongo2.Value
|
||||
// AsValue converts any given value to a pongo2.Value
|
||||
// Usually being used within own functions passed to a template
|
||||
// through a Context or within filter functions.
|
||||
//
|
||||
|
@ -24,7 +25,7 @@ func AsValue(i interface{}) *Value {
|
|||
}
|
||||
}
|
||||
|
||||
// Like AsValue, but does not apply the 'escape' filter.
|
||||
// AsSafeValue works like AsValue, but does not apply the 'escape' filter.
|
||||
func AsSafeValue(i interface{}) *Value {
|
||||
return &Value{
|
||||
val: reflect.ValueOf(i),
|
||||
|
@ -39,23 +40,23 @@ func (v *Value) getResolvedValue() reflect.Value {
|
|||
return v.val
|
||||
}
|
||||
|
||||
// Checks whether the underlying value is a string
|
||||
// IsString checks whether the underlying value is a string
|
||||
func (v *Value) IsString() bool {
|
||||
return v.getResolvedValue().Kind() == reflect.String
|
||||
}
|
||||
|
||||
// Checks whether the underlying value is a bool
|
||||
// IsBool checks whether the underlying value is a bool
|
||||
func (v *Value) IsBool() bool {
|
||||
return v.getResolvedValue().Kind() == reflect.Bool
|
||||
}
|
||||
|
||||
// Checks whether the underlying value is a float
|
||||
// IsFloat checks whether the underlying value is a float
|
||||
func (v *Value) IsFloat() bool {
|
||||
return v.getResolvedValue().Kind() == reflect.Float32 ||
|
||||
v.getResolvedValue().Kind() == reflect.Float64
|
||||
}
|
||||
|
||||
// Checks whether the underlying value is an integer
|
||||
// IsInteger checks whether the underlying value is an integer
|
||||
func (v *Value) IsInteger() bool {
|
||||
return v.getResolvedValue().Kind() == reflect.Int ||
|
||||
v.getResolvedValue().Kind() == reflect.Int8 ||
|
||||
|
@ -69,19 +70,19 @@ func (v *Value) IsInteger() bool {
|
|||
v.getResolvedValue().Kind() == reflect.Uint64
|
||||
}
|
||||
|
||||
// Checks whether the underlying value is either an integer
|
||||
// IsNumber checks whether the underlying value is either an integer
|
||||
// or a float.
|
||||
func (v *Value) IsNumber() bool {
|
||||
return v.IsInteger() || v.IsFloat()
|
||||
}
|
||||
|
||||
// Checks whether the underlying value is NIL
|
||||
// IsNil checks whether the underlying value is NIL
|
||||
func (v *Value) IsNil() bool {
|
||||
//fmt.Printf("%+v\n", v.getResolvedValue().Type().String())
|
||||
return !v.getResolvedValue().IsValid()
|
||||
}
|
||||
|
||||
// Returns a string for the underlying value. If this value is not
|
||||
// String returns a string for the underlying value. If this value is not
|
||||
// of type string, pongo2 tries to convert it. Currently the following
|
||||
// types for underlying values are supported:
|
||||
//
|
||||
|
@ -111,9 +112,8 @@ func (v *Value) String() string {
|
|||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
return "True"
|
||||
} else {
|
||||
return "False"
|
||||
}
|
||||
return "False"
|
||||
case reflect.Struct:
|
||||
if t, ok := v.Interface().(fmt.Stringer); ok {
|
||||
return t.String()
|
||||
|
@ -124,7 +124,7 @@ func (v *Value) String() string {
|
|||
return v.getResolvedValue().String()
|
||||
}
|
||||
|
||||
// Returns the underlying value as an integer (converts the underlying
|
||||
// Integer returns the underlying value as an integer (converts the underlying
|
||||
// value, if necessary). If it's not possible to convert the underlying value,
|
||||
// it will return 0.
|
||||
func (v *Value) Integer() int {
|
||||
|
@ -148,7 +148,7 @@ func (v *Value) Integer() int {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns the underlying value as a float (converts the underlying
|
||||
// Float returns the underlying value as a float (converts the underlying
|
||||
// value, if necessary). If it's not possible to convert the underlying value,
|
||||
// it will return 0.0.
|
||||
func (v *Value) Float() float64 {
|
||||
|
@ -172,7 +172,7 @@ func (v *Value) Float() float64 {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns the underlying value as bool. If the value is not bool, false
|
||||
// Bool returns the underlying value as bool. If the value is not bool, false
|
||||
// will always be returned. If you're looking for true/false-evaluation of the
|
||||
// underlying value, have a look on the IsTrue()-function.
|
||||
func (v *Value) Bool() bool {
|
||||
|
@ -185,7 +185,7 @@ func (v *Value) Bool() bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Tries to evaluate the underlying value the Pythonic-way:
|
||||
// IsTrue tries to evaluate the underlying value the Pythonic-way:
|
||||
//
|
||||
// Returns TRUE in one the following cases:
|
||||
//
|
||||
|
@ -217,7 +217,7 @@ func (v *Value) IsTrue() bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Tries to negate the underlying value. It's mainly used for
|
||||
// Negate tries to negate the underlying value. It's mainly used for
|
||||
// the NOT-operator and in conjunction with a call to
|
||||
// return_value.IsTrue() afterwards.
|
||||
//
|
||||
|
@ -229,26 +229,26 @@ func (v *Value) Negate() *Value {
|
|||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if v.Integer() != 0 {
|
||||
return AsValue(0)
|
||||
} else {
|
||||
return AsValue(1)
|
||||
}
|
||||
return AsValue(1)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if v.Float() != 0.0 {
|
||||
return AsValue(float64(0.0))
|
||||
} else {
|
||||
return AsValue(float64(1.1))
|
||||
}
|
||||
return AsValue(float64(1.1))
|
||||
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
|
||||
return AsValue(v.getResolvedValue().Len() == 0)
|
||||
case reflect.Bool:
|
||||
return AsValue(!v.getResolvedValue().Bool())
|
||||
case reflect.Struct:
|
||||
return AsValue(false)
|
||||
default:
|
||||
logf("Value.IsTrue() not available for type: %s\n", v.getResolvedValue().Kind().String())
|
||||
return AsValue(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the length for an array, chan, map, slice or string.
|
||||
// Len returns the length for an array, chan, map, slice or string.
|
||||
// Otherwise it will return 0.
|
||||
func (v *Value) Len() int {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
|
@ -263,7 +263,7 @@ func (v *Value) Len() int {
|
|||
}
|
||||
}
|
||||
|
||||
// Slices an array, slice or string. Otherwise it will
|
||||
// Slice slices an array, slice or string. Otherwise it will
|
||||
// return an empty []int.
|
||||
func (v *Value) Slice(i, j int) *Value {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
|
@ -278,7 +278,7 @@ func (v *Value) Slice(i, j int) *Value {
|
|||
}
|
||||
}
|
||||
|
||||
// Get the i-th item of an array, slice or string. Otherwise
|
||||
// Index gets the i-th item of an array, slice or string. Otherwise
|
||||
// it will return NIL.
|
||||
func (v *Value) Index(i int) *Value {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
|
@ -301,7 +301,7 @@ func (v *Value) Index(i int) *Value {
|
|||
}
|
||||
}
|
||||
|
||||
// Checks whether the underlying value (which must be of type struct, map,
|
||||
// Contains checks whether the underlying value (which must be of type struct, map,
|
||||
// string, array or slice) contains of another Value (e. g. used to check
|
||||
// whether a struct contains of a specific field or a map contains a specific key).
|
||||
//
|
||||
|
@ -310,25 +310,32 @@ func (v *Value) Index(i int) *Value {
|
|||
func (v *Value) Contains(other *Value) bool {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
case reflect.Struct:
|
||||
field_value := v.getResolvedValue().FieldByName(other.String())
|
||||
return field_value.IsValid()
|
||||
fieldValue := v.getResolvedValue().FieldByName(other.String())
|
||||
return fieldValue.IsValid()
|
||||
case reflect.Map:
|
||||
var map_value reflect.Value
|
||||
var mapValue reflect.Value
|
||||
switch other.Interface().(type) {
|
||||
case int:
|
||||
map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
case string:
|
||||
map_value = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
mapValue = v.getResolvedValue().MapIndex(other.getResolvedValue())
|
||||
default:
|
||||
logf("Value.Contains() does not support lookup type '%s'\n", other.getResolvedValue().Kind().String())
|
||||
return false
|
||||
}
|
||||
|
||||
return map_value.IsValid()
|
||||
return mapValue.IsValid()
|
||||
case reflect.String:
|
||||
return strings.Contains(v.getResolvedValue().String(), other.String())
|
||||
|
||||
// TODO: reflect.Array, reflect.Slice
|
||||
case reflect.Slice, reflect.Array:
|
||||
for i := 0; i < v.getResolvedValue().Len(); i++ {
|
||||
item := v.getResolvedValue().Index(i)
|
||||
if other.Interface() == item.Interface() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
default:
|
||||
logf("Value.Contains() not available for type: %s\n", v.getResolvedValue().Kind().String())
|
||||
|
@ -336,7 +343,7 @@ func (v *Value) Contains(other *Value) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Checks whether the underlying value is of type array, slice or string.
|
||||
// CanSlice checks whether the underlying value is of type array, slice or string.
|
||||
// You normally would use CanSlice() before using the Slice() operation.
|
||||
func (v *Value) CanSlice() bool {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
|
@ -346,7 +353,7 @@ func (v *Value) CanSlice() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Iterates over a map, array, slice or a string. It calls the
|
||||
// Iterate iterates over a map, array, slice or a string. It calls the
|
||||
// function's first argument for every value with the following arguments:
|
||||
//
|
||||
// idx current 0-index
|
||||
|
@ -357,16 +364,23 @@ func (v *Value) CanSlice() bool {
|
|||
// If the underlying value has no items or is not one of the types above,
|
||||
// the empty function (function's second argument) will be called.
|
||||
func (v *Value) Iterate(fn func(idx, count int, key, value *Value) bool, empty func()) {
|
||||
v.IterateOrder(fn, empty, false)
|
||||
v.IterateOrder(fn, empty, false, false)
|
||||
}
|
||||
|
||||
// Like Value.Iterate, but can iterate through an array/slice/string in reverse. Does
|
||||
// IterateOrder behaves like Value.Iterate, but can iterate through an array/slice/string in reverse. Does
|
||||
// not affect the iteration through a map because maps don't have any particular order.
|
||||
func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, empty func(), reverse bool) {
|
||||
// However, you can force an order using the `sorted` keyword (and even use `reversed sorted`).
|
||||
func (v *Value) IterateOrder(fn func(idx, count int, key, value *Value) bool, empty func(), reverse bool, sorted bool) {
|
||||
switch v.getResolvedValue().Kind() {
|
||||
case reflect.Map:
|
||||
// Reverse not needed for maps, since they are not ordered
|
||||
keys := v.getResolvedValue().MapKeys()
|
||||
keys := sortedKeys(v.getResolvedValue().MapKeys())
|
||||
if sorted {
|
||||
if reverse {
|
||||
sort.Sort(sort.Reverse(keys))
|
||||
} else {
|
||||
sort.Sort(keys)
|
||||
}
|
||||
}
|
||||
keyLen := len(keys)
|
||||
for idx, key := range keys {
|
||||
value := v.getResolvedValue().MapIndex(key)
|
||||
|
@ -379,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]
|
||||
}
|
||||
|
|
286
vendor/github.com/flosch/pongo2/variable.go
generated
vendored
286
vendor/github.com/flosch/pongo2/variable.go
generated
vendored
|
@ -1,11 +1,12 @@
|
|||
package pongo2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -13,13 +14,18 @@ const (
|
|||
varTypeIdent
|
||||
)
|
||||
|
||||
var (
|
||||
typeOfValuePtr = reflect.TypeOf(new(Value))
|
||||
typeOfExecCtxPtr = reflect.TypeOf(new(ExecutionContext))
|
||||
)
|
||||
|
||||
type variablePart struct {
|
||||
typ int
|
||||
s string
|
||||
i int
|
||||
|
||||
is_function_call bool
|
||||
calling_args []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
|
||||
isFunctionCall bool
|
||||
callingArgs []functionCallArgument // needed for a function call, represents all argument nodes (INode supports nested function calls)
|
||||
}
|
||||
|
||||
type functionCallArgument interface {
|
||||
|
@ -28,119 +34,121 @@ type functionCallArgument interface {
|
|||
|
||||
// TODO: Add location tokens
|
||||
type stringResolver struct {
|
||||
location_token *Token
|
||||
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 '{{'
|
||||
|
|
191
vendor/github.com/juju/errors/LICENSE
generated
vendored
Normal file
191
vendor/github.com/juju/errors/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
All files in this repository are licensed as follows. If you contribute
|
||||
to this repository, it is assumed that you license your contribution
|
||||
under the same license unless you state otherwise.
|
||||
|
||||
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
|
||||
|
||||
This software is licensed under the LGPLv3, included below.
|
||||
|
||||
As a special exception to the GNU Lesser General Public License version 3
|
||||
("LGPL3"), the copyright holders of this Library give you permission to
|
||||
convey to a third party a Combined Work that links statically or dynamically
|
||||
to this Library without providing any Minimal Corresponding Source or
|
||||
Minimal Application Code as set out in 4d or providing the installation
|
||||
information set out in section 4e, provided that you comply with the other
|
||||
provisions of LGPL3 and provided that you meet, for the Application the
|
||||
terms and conditions of the license(s) which apply to the Application.
|
||||
|
||||
Except as stated in this special exception, the provisions of LGPL3 will
|
||||
continue to comply in full to this Library. If you modify this Library, you
|
||||
may apply this exception to your version of this Library, but you are not
|
||||
obliged to do so. If you do not wish to do so, delete this exception
|
||||
statement from your version. This exception does not (and cannot) modify any
|
||||
license terms which apply to the Application, with which you must still
|
||||
comply.
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
11
vendor/github.com/juju/errors/Makefile
generated
vendored
Normal file
11
vendor/github.com/juju/errors/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
default: check
|
||||
|
||||
check:
|
||||
go test && go test -compiler gccgo
|
||||
|
||||
docs:
|
||||
godoc2md github.com/juju/errors > README.md
|
||||
sed -i 's|\[godoc-link-here\]|[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)|' README.md
|
||||
|
||||
|
||||
.PHONY: default check docs
|
543
vendor/github.com/juju/errors/README.md
generated
vendored
Normal file
543
vendor/github.com/juju/errors/README.md
generated
vendored
Normal file
|
@ -0,0 +1,543 @@
|
|||
|
||||
# errors
|
||||
import "github.com/juju/errors"
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/juju/errors?status.svg)](https://godoc.org/github.com/juju/errors)
|
||||
|
||||
The juju/errors provides an easy way to annotate errors without losing the
|
||||
orginal error context.
|
||||
|
||||
The exported `New` and `Errorf` functions are designed to replace the
|
||||
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
|
||||
error is there, but the package also records the location at which the error
|
||||
was created.
|
||||
|
||||
A primary use case for this library is to add extra context any time an
|
||||
error is returned from a function.
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
This instead becomes:
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
which just records the file and line number of the Trace call, or
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Annotate(err, "more context")
|
||||
}
|
||||
|
||||
which also adds an annotation to the error.
|
||||
|
||||
When you want to check to see if an error is of a particular type, a helper
|
||||
function is normally exported by the package that returned the error, like the
|
||||
`os` package does. The underlying cause of the error is available using the
|
||||
`Cause` function.
|
||||
|
||||
|
||||
os.IsNotExist(errors.Cause(err))
|
||||
|
||||
The result of the `Error()` call on an annotated error is the annotations joined
|
||||
with colons, then the result of the `Error()` method for the underlying error
|
||||
that was the cause.
|
||||
|
||||
|
||||
err := errors.Errorf("original")
|
||||
err = errors.Annotatef(err, "context")
|
||||
err = errors.Annotatef(err, "more context")
|
||||
err.Error() -> "more context: context: original"
|
||||
|
||||
Obviously recording the file, line and functions is not very useful if you
|
||||
cannot get them back out again.
|
||||
|
||||
|
||||
errors.ErrorStack(err)
|
||||
|
||||
will return something like:
|
||||
|
||||
|
||||
first error
|
||||
github.com/juju/errors/annotation_test.go:193:
|
||||
github.com/juju/errors/annotation_test.go:194: annotation
|
||||
github.com/juju/errors/annotation_test.go:195:
|
||||
github.com/juju/errors/annotation_test.go:196: more context
|
||||
github.com/juju/errors/annotation_test.go:197:
|
||||
|
||||
The first error was generated by an external system, so there was no location
|
||||
associated. The second, fourth, and last lines were generated with Trace calls,
|
||||
and the other two through Annotate.
|
||||
|
||||
Sometimes when responding to an error you want to return a more specific error
|
||||
for the situation.
|
||||
|
||||
|
||||
if err := FindField(field); err != nil {
|
||||
return errors.Wrap(err, errors.NotFoundf(field))
|
||||
}
|
||||
|
||||
This returns an error where the complete error stack is still available, and
|
||||
`errors.Cause()` will return the `NotFound` error.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## func AlreadyExistsf
|
||||
``` go
|
||||
func AlreadyExistsf(format string, args ...interface{}) error
|
||||
```
|
||||
AlreadyExistsf returns an error which satisfies IsAlreadyExists().
|
||||
|
||||
|
||||
## func Annotate
|
||||
``` go
|
||||
func Annotate(other error, message string) error
|
||||
```
|
||||
Annotate is used to add extra context to an existing error. The location of
|
||||
the Annotate call is recorded with the annotations. The file, line and
|
||||
function are also recorded.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Annotate(err, "failed to frombulate")
|
||||
}
|
||||
|
||||
|
||||
## func Annotatef
|
||||
``` go
|
||||
func Annotatef(other error, format string, args ...interface{}) error
|
||||
```
|
||||
Annotatef is used to add extra context to an existing error. The location of
|
||||
the Annotate call is recorded with the annotations. The file, line and
|
||||
function are also recorded.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Annotatef(err, "failed to frombulate the %s", arg)
|
||||
}
|
||||
|
||||
|
||||
## func Cause
|
||||
``` go
|
||||
func Cause(err error) error
|
||||
```
|
||||
Cause returns the cause of the given error. This will be either the
|
||||
original error, or the result of a Wrap or Mask call.
|
||||
|
||||
Cause is the usual way to diagnose errors that may have been wrapped by
|
||||
the other errors functions.
|
||||
|
||||
|
||||
## func DeferredAnnotatef
|
||||
``` go
|
||||
func DeferredAnnotatef(err *error, format string, args ...interface{})
|
||||
```
|
||||
DeferredAnnotatef annotates the given error (when it is not nil) with the given
|
||||
format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
|
||||
does nothing. This method is used in a defer statement in order to annotate any
|
||||
resulting error with the same message.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
|
||||
|
||||
|
||||
## func Details
|
||||
``` go
|
||||
func Details(err error) string
|
||||
```
|
||||
Details returns information about the stack of errors wrapped by err, in
|
||||
the format:
|
||||
|
||||
|
||||
[{filename:99: error one} {otherfile:55: cause of error one}]
|
||||
|
||||
This is a terse alternative to ErrorStack as it returns a single line.
|
||||
|
||||
|
||||
## func ErrorStack
|
||||
``` go
|
||||
func ErrorStack(err error) string
|
||||
```
|
||||
ErrorStack returns a string representation of the annotated error. If the
|
||||
error passed as the parameter is not an annotated error, the result is
|
||||
simply the result of the Error() method on that error.
|
||||
|
||||
If the error is an annotated error, a multi-line string is returned where
|
||||
each line represents one entry in the annotation stack. The full filename
|
||||
from the call stack is used in the output.
|
||||
|
||||
|
||||
first error
|
||||
github.com/juju/errors/annotation_test.go:193:
|
||||
github.com/juju/errors/annotation_test.go:194: annotation
|
||||
github.com/juju/errors/annotation_test.go:195:
|
||||
github.com/juju/errors/annotation_test.go:196: more context
|
||||
github.com/juju/errors/annotation_test.go:197:
|
||||
|
||||
|
||||
## func Errorf
|
||||
``` go
|
||||
func Errorf(format string, args ...interface{}) error
|
||||
```
|
||||
Errorf creates a new annotated error and records the location that the
|
||||
error is created. This should be a drop in replacement for fmt.Errorf.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
return errors.Errorf("validation failed: %s", message)
|
||||
|
||||
|
||||
## func IsAlreadyExists
|
||||
``` go
|
||||
func IsAlreadyExists(err error) bool
|
||||
```
|
||||
IsAlreadyExists reports whether the error was created with
|
||||
AlreadyExistsf() or NewAlreadyExists().
|
||||
|
||||
|
||||
## func IsNotFound
|
||||
``` go
|
||||
func IsNotFound(err error) bool
|
||||
```
|
||||
IsNotFound reports whether err was created with NotFoundf() or
|
||||
NewNotFound().
|
||||
|
||||
|
||||
## func IsNotImplemented
|
||||
``` go
|
||||
func IsNotImplemented(err error) bool
|
||||
```
|
||||
IsNotImplemented reports whether err was created with
|
||||
NotImplementedf() or NewNotImplemented().
|
||||
|
||||
|
||||
## func IsNotSupported
|
||||
``` go
|
||||
func IsNotSupported(err error) bool
|
||||
```
|
||||
IsNotSupported reports whether the error was created with
|
||||
NotSupportedf() or NewNotSupported().
|
||||
|
||||
|
||||
## func IsNotValid
|
||||
``` go
|
||||
func IsNotValid(err error) bool
|
||||
```
|
||||
IsNotValid reports whether the error was created with NotValidf() or
|
||||
NewNotValid().
|
||||
|
||||
|
||||
## func IsUnauthorized
|
||||
``` go
|
||||
func IsUnauthorized(err error) bool
|
||||
```
|
||||
IsUnauthorized reports whether err was created with Unauthorizedf() or
|
||||
NewUnauthorized().
|
||||
|
||||
|
||||
## func Mask
|
||||
``` go
|
||||
func Mask(other error) error
|
||||
```
|
||||
Mask hides the underlying error type, and records the location of the masking.
|
||||
|
||||
|
||||
## func Maskf
|
||||
``` go
|
||||
func Maskf(other error, format string, args ...interface{}) error
|
||||
```
|
||||
Mask masks the given error with the given format string and arguments (like
|
||||
fmt.Sprintf), returning a new error that maintains the error stack, but
|
||||
hides the underlying error type. The error string still contains the full
|
||||
annotations. If you want to hide the annotations, call Wrap.
|
||||
|
||||
|
||||
## func New
|
||||
``` go
|
||||
func New(message string) error
|
||||
```
|
||||
New is a drop in replacement for the standard libary errors module that records
|
||||
the location that the error is created.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
return errors.New("validation failed")
|
||||
|
||||
|
||||
## func NewAlreadyExists
|
||||
``` go
|
||||
func NewAlreadyExists(err error, msg string) error
|
||||
```
|
||||
NewAlreadyExists returns an error which wraps err and satisfies
|
||||
IsAlreadyExists().
|
||||
|
||||
|
||||
## func NewNotFound
|
||||
``` go
|
||||
func NewNotFound(err error, msg string) error
|
||||
```
|
||||
NewNotFound returns an error which wraps err that satisfies
|
||||
IsNotFound().
|
||||
|
||||
|
||||
## func NewNotImplemented
|
||||
``` go
|
||||
func NewNotImplemented(err error, msg string) error
|
||||
```
|
||||
NewNotImplemented returns an error which wraps err and satisfies
|
||||
IsNotImplemented().
|
||||
|
||||
|
||||
## func NewNotSupported
|
||||
``` go
|
||||
func NewNotSupported(err error, msg string) error
|
||||
```
|
||||
NewNotSupported returns an error which wraps err and satisfies
|
||||
IsNotSupported().
|
||||
|
||||
|
||||
## func NewNotValid
|
||||
``` go
|
||||
func NewNotValid(err error, msg string) error
|
||||
```
|
||||
NewNotValid returns an error which wraps err and satisfies IsNotValid().
|
||||
|
||||
|
||||
## func NewUnauthorized
|
||||
``` go
|
||||
func NewUnauthorized(err error, msg string) error
|
||||
```
|
||||
NewUnauthorized returns an error which wraps err and satisfies
|
||||
IsUnauthorized().
|
||||
|
||||
|
||||
## func NotFoundf
|
||||
``` go
|
||||
func NotFoundf(format string, args ...interface{}) error
|
||||
```
|
||||
NotFoundf returns an error which satisfies IsNotFound().
|
||||
|
||||
|
||||
## func NotImplementedf
|
||||
``` go
|
||||
func NotImplementedf(format string, args ...interface{}) error
|
||||
```
|
||||
NotImplementedf returns an error which satisfies IsNotImplemented().
|
||||
|
||||
|
||||
## func NotSupportedf
|
||||
``` go
|
||||
func NotSupportedf(format string, args ...interface{}) error
|
||||
```
|
||||
NotSupportedf returns an error which satisfies IsNotSupported().
|
||||
|
||||
|
||||
## func NotValidf
|
||||
``` go
|
||||
func NotValidf(format string, args ...interface{}) error
|
||||
```
|
||||
NotValidf returns an error which satisfies IsNotValid().
|
||||
|
||||
|
||||
## func Trace
|
||||
``` go
|
||||
func Trace(other error) error
|
||||
```
|
||||
Trace adds the location of the Trace call to the stack. The Cause of the
|
||||
resulting error is the same as the error parameter. If the other error is
|
||||
nil, the result will be nil.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
|
||||
## func Unauthorizedf
|
||||
``` go
|
||||
func Unauthorizedf(format string, args ...interface{}) error
|
||||
```
|
||||
Unauthorizedf returns an error which satisfies IsUnauthorized().
|
||||
|
||||
|
||||
## func Forbiddenf
|
||||
``` go
|
||||
func Forbiddenf(format string, args ...interface{}) error
|
||||
```
|
||||
Forbiddenf returns an error which satisfies IsForbidden().
|
||||
|
||||
|
||||
## func Wrap
|
||||
``` go
|
||||
func Wrap(other, newDescriptive error) error
|
||||
```
|
||||
Wrap changes the Cause of the error. The location of the Wrap call is also
|
||||
stored in the error stack.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
newErr := &packageError{"more context", private_value}
|
||||
return errors.Wrap(err, newErr)
|
||||
}
|
||||
|
||||
|
||||
## func Wrapf
|
||||
``` go
|
||||
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error
|
||||
```
|
||||
Wrapf changes the Cause of the error, and adds an annotation. The location
|
||||
of the Wrap call is also stored in the error stack.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
|
||||
}
|
||||
|
||||
|
||||
|
||||
## type Err
|
||||
``` go
|
||||
type Err struct {
|
||||
// contains filtered or unexported fields
|
||||
}
|
||||
```
|
||||
Err holds a description of an error along with information about
|
||||
where the error was created.
|
||||
|
||||
It may be embedded in custom error types to add extra information that
|
||||
this errors package can understand.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### func NewErr
|
||||
``` go
|
||||
func NewErr(format string, args ...interface{}) Err
|
||||
```
|
||||
NewErr is used to return an Err for the purpose of embedding in other
|
||||
structures. The location is not specified, and needs to be set with a call
|
||||
to SetLocation.
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
type FooError struct {
|
||||
errors.Err
|
||||
code int
|
||||
}
|
||||
|
||||
func NewFooError(code int) error {
|
||||
err := &FooError{errors.NewErr("foo"), code}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
### func (\*Err) Cause
|
||||
``` go
|
||||
func (e *Err) Cause() error
|
||||
```
|
||||
The Cause of an error is the most recent error in the error stack that
|
||||
meets one of these criteria: the original error that was raised; the new
|
||||
error that was passed into the Wrap function; the most recently masked
|
||||
error; or nil if the error itself is considered the Cause. Normally this
|
||||
method is not invoked directly, but instead through the Cause stand alone
|
||||
function.
|
||||
|
||||
|
||||
|
||||
### func (\*Err) Error
|
||||
``` go
|
||||
func (e *Err) Error() string
|
||||
```
|
||||
Error implements error.Error.
|
||||
|
||||
|
||||
|
||||
### func (\*Err) Location
|
||||
``` go
|
||||
func (e *Err) Location() (filename string, line int)
|
||||
```
|
||||
Location is the file and line of where the error was most recently
|
||||
created or annotated.
|
||||
|
||||
|
||||
|
||||
### func (\*Err) Message
|
||||
``` go
|
||||
func (e *Err) Message() string
|
||||
```
|
||||
Message returns the message stored with the most recent location. This is
|
||||
the empty string if the most recent call was Trace, or the message stored
|
||||
with Annotate or Mask.
|
||||
|
||||
|
||||
|
||||
### func (\*Err) SetLocation
|
||||
``` go
|
||||
func (e *Err) SetLocation(callDepth int)
|
||||
```
|
||||
SetLocation records the source location of the error at callDepth stack
|
||||
frames above the call.
|
||||
|
||||
|
||||
|
||||
### func (\*Err) StackTrace
|
||||
``` go
|
||||
func (e *Err) StackTrace() []string
|
||||
```
|
||||
StackTrace returns one string for each location recorded in the stack of
|
||||
errors. The first value is the originating error, with a line for each
|
||||
other annotation or tracing of the error.
|
||||
|
||||
|
||||
|
||||
### func (\*Err) Underlying
|
||||
``` go
|
||||
func (e *Err) Underlying() error
|
||||
```
|
||||
Underlying returns the previous error in the error stack, if any. A client
|
||||
should not ever really call this method. It is used to build the error
|
||||
stack and should not be introspected by client calls. Or more
|
||||
specifically, clients should not depend on anything but the `Cause` of an
|
||||
error.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- - -
|
||||
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)
|
81
vendor/github.com/juju/errors/doc.go
generated
vendored
Normal file
81
vendor/github.com/juju/errors/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2013, 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
/*
|
||||
[godoc-link-here]
|
||||
|
||||
The juju/errors provides an easy way to annotate errors without losing the
|
||||
orginal error context.
|
||||
|
||||
The exported `New` and `Errorf` functions are designed to replace the
|
||||
`errors.New` and `fmt.Errorf` functions respectively. The same underlying
|
||||
error is there, but the package also records the location at which the error
|
||||
was created.
|
||||
|
||||
A primary use case for this library is to add extra context any time an
|
||||
error is returned from a function.
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
This instead becomes:
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Trace(err)
|
||||
}
|
||||
|
||||
which just records the file and line number of the Trace call, or
|
||||
|
||||
if err := SomeFunc(); err != nil {
|
||||
return errors.Annotate(err, "more context")
|
||||
}
|
||||
|
||||
which also adds an annotation to the error.
|
||||
|
||||
When you want to check to see if an error is of a particular type, a helper
|
||||
function is normally exported by the package that returned the error, like the
|
||||
`os` package does. The underlying cause of the error is available using the
|
||||
`Cause` function.
|
||||
|
||||
os.IsNotExist(errors.Cause(err))
|
||||
|
||||
The result of the `Error()` call on an annotated error is the annotations joined
|
||||
with colons, then the result of the `Error()` method for the underlying error
|
||||
that was the cause.
|
||||
|
||||
err := errors.Errorf("original")
|
||||
err = errors.Annotatef(err, "context")
|
||||
err = errors.Annotatef(err, "more context")
|
||||
err.Error() -> "more context: context: original"
|
||||
|
||||
Obviously recording the file, line and functions is not very useful if you
|
||||
cannot get them back out again.
|
||||
|
||||
errors.ErrorStack(err)
|
||||
|
||||
will return something like:
|
||||
|
||||
first error
|
||||
github.com/juju/errors/annotation_test.go:193:
|
||||
github.com/juju/errors/annotation_test.go:194: annotation
|
||||
github.com/juju/errors/annotation_test.go:195:
|
||||
github.com/juju/errors/annotation_test.go:196: more context
|
||||
github.com/juju/errors/annotation_test.go:197:
|
||||
|
||||
The first error was generated by an external system, so there was no location
|
||||
associated. The second, fourth, and last lines were generated with Trace calls,
|
||||
and the other two through Annotate.
|
||||
|
||||
Sometimes when responding to an error you want to return a more specific error
|
||||
for the situation.
|
||||
|
||||
if err := FindField(field); err != nil {
|
||||
return errors.Wrap(err, errors.NotFoundf(field))
|
||||
}
|
||||
|
||||
This returns an error where the complete error stack is still available, and
|
||||
`errors.Cause()` will return the `NotFound` error.
|
||||
|
||||
*/
|
||||
package errors
|
172
vendor/github.com/juju/errors/error.go
generated
vendored
Normal file
172
vendor/github.com/juju/errors/error.go
generated
vendored
Normal file
|
@ -0,0 +1,172 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// Err holds a description of an error along with information about
|
||||
// where the error was created.
|
||||
//
|
||||
// It may be embedded in custom error types to add extra information that
|
||||
// this errors package can understand.
|
||||
type Err struct {
|
||||
// message holds an annotation of the error.
|
||||
message string
|
||||
|
||||
// cause holds the cause of the error as returned
|
||||
// by the Cause method.
|
||||
cause error
|
||||
|
||||
// previous holds the previous error in the error stack, if any.
|
||||
previous error
|
||||
|
||||
// file and line hold the source code location where the error was
|
||||
// created.
|
||||
file string
|
||||
line int
|
||||
}
|
||||
|
||||
// NewErr is used to return an Err for the purpose of embedding in other
|
||||
// structures. The location is not specified, and needs to be set with a call
|
||||
// to SetLocation.
|
||||
//
|
||||
// For example:
|
||||
// type FooError struct {
|
||||
// errors.Err
|
||||
// code int
|
||||
// }
|
||||
//
|
||||
// func NewFooError(code int) error {
|
||||
// err := &FooError{errors.NewErr("foo"), code}
|
||||
// err.SetLocation(1)
|
||||
// return err
|
||||
// }
|
||||
func NewErr(format string, args ...interface{}) Err {
|
||||
return Err{
|
||||
message: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewErrWithCause is used to return an Err with case by other error for the purpose of embedding in other
|
||||
// structures. The location is not specified, and needs to be set with a call
|
||||
// to SetLocation.
|
||||
//
|
||||
// For example:
|
||||
// type FooError struct {
|
||||
// errors.Err
|
||||
// code int
|
||||
// }
|
||||
//
|
||||
// func (e *FooError) Annotate(format string, args ...interface{}) error {
|
||||
// err := &FooError{errors.NewErrWithCause(e.Err, format, args...), e.code}
|
||||
// err.SetLocation(1)
|
||||
// return err
|
||||
// })
|
||||
func NewErrWithCause(other error, format string, args ...interface{}) Err {
|
||||
return Err{
|
||||
message: fmt.Sprintf(format, args...),
|
||||
cause: Cause(other),
|
||||
previous: other,
|
||||
}
|
||||
}
|
||||
|
||||
// Location is the file and line of where the error was most recently
|
||||
// created or annotated.
|
||||
func (e *Err) Location() (filename string, line int) {
|
||||
return e.file, e.line
|
||||
}
|
||||
|
||||
// Underlying returns the previous error in the error stack, if any. A client
|
||||
// should not ever really call this method. It is used to build the error
|
||||
// stack and should not be introspected by client calls. Or more
|
||||
// specifically, clients should not depend on anything but the `Cause` of an
|
||||
// error.
|
||||
func (e *Err) Underlying() error {
|
||||
return e.previous
|
||||
}
|
||||
|
||||
// The Cause of an error is the most recent error in the error stack that
|
||||
// meets one of these criteria: the original error that was raised; the new
|
||||
// error that was passed into the Wrap function; the most recently masked
|
||||
// error; or nil if the error itself is considered the Cause. Normally this
|
||||
// method is not invoked directly, but instead through the Cause stand alone
|
||||
// function.
|
||||
func (e *Err) Cause() error {
|
||||
return e.cause
|
||||
}
|
||||
|
||||
// Message returns the message stored with the most recent location. This is
|
||||
// the empty string if the most recent call was Trace, or the message stored
|
||||
// with Annotate or Mask.
|
||||
func (e *Err) Message() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
// Error implements error.Error.
|
||||
func (e *Err) Error() string {
|
||||
// We want to walk up the stack of errors showing the annotations
|
||||
// as long as the cause is the same.
|
||||
err := e.previous
|
||||
if !sameError(Cause(err), e.cause) && e.cause != nil {
|
||||
err = e.cause
|
||||
}
|
||||
switch {
|
||||
case err == nil:
|
||||
return e.message
|
||||
case e.message == "":
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("%s: %v", e.message, err)
|
||||
}
|
||||
|
||||
// Format implements fmt.Formatter
|
||||
// When printing errors with %+v it also prints the stack trace.
|
||||
// %#v unsurprisingly will print the real underlying type.
|
||||
func (e *Err) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
fmt.Fprintf(s, "%s", ErrorStack(e))
|
||||
return
|
||||
case s.Flag('#'):
|
||||
// avoid infinite recursion by wrapping e into a type
|
||||
// that doesn't implement Formatter.
|
||||
fmt.Fprintf(s, "%#v", (*unformatter)(e))
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
fmt.Fprintf(s, "%s", e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// helper for Format
|
||||
type unformatter Err
|
||||
|
||||
func (unformatter) Format() { /* break the fmt.Formatter interface */ }
|
||||
|
||||
// SetLocation records the source location of the error at callDepth stack
|
||||
// frames above the call.
|
||||
func (e *Err) SetLocation(callDepth int) {
|
||||
_, file, line, _ := runtime.Caller(callDepth + 1)
|
||||
e.file = trimGoPath(file)
|
||||
e.line = line
|
||||
}
|
||||
|
||||
// StackTrace returns one string for each location recorded in the stack of
|
||||
// errors. The first value is the originating error, with a line for each
|
||||
// other annotation or tracing of the error.
|
||||
func (e *Err) StackTrace() []string {
|
||||
return errorStack(e)
|
||||
}
|
||||
|
||||
// Ideally we'd have a way to check identity, but deep equals will do.
|
||||
func sameError(e1, e2 error) bool {
|
||||
return reflect.DeepEqual(e1, e2)
|
||||
}
|
178
vendor/github.com/juju/errors/error_test.go
generated
vendored
Normal file
178
vendor/github.com/juju/errors/error_test.go
generated
vendored
Normal file
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
jc "github.com/juju/testing/checkers"
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type errorsSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&errorsSuite{})
|
||||
|
||||
var someErr = errors.New("some error") //err varSomeErr
|
||||
|
||||
func (*errorsSuite) TestErrorString(c *gc.C) {
|
||||
for i, test := range []struct {
|
||||
message string
|
||||
generator func() error
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
message: "uncomparable errors",
|
||||
generator: func() error {
|
||||
err := errors.Annotatef(newNonComparableError("uncomparable"), "annotation")
|
||||
return errors.Annotatef(err, "another")
|
||||
},
|
||||
expected: "another: annotation: uncomparable",
|
||||
}, {
|
||||
message: "Errorf",
|
||||
generator: func() error {
|
||||
return errors.Errorf("first error")
|
||||
},
|
||||
expected: "first error",
|
||||
}, {
|
||||
message: "annotated error",
|
||||
generator: func() error {
|
||||
err := errors.Errorf("first error")
|
||||
return errors.Annotatef(err, "annotation")
|
||||
},
|
||||
expected: "annotation: first error",
|
||||
}, {
|
||||
message: "test annotation format",
|
||||
generator: func() error {
|
||||
err := errors.Errorf("first %s", "error")
|
||||
return errors.Annotatef(err, "%s", "annotation")
|
||||
},
|
||||
expected: "annotation: first error",
|
||||
}, {
|
||||
message: "wrapped error",
|
||||
generator: func() error {
|
||||
err := newError("first error")
|
||||
return errors.Wrap(err, newError("detailed error"))
|
||||
},
|
||||
expected: "detailed error",
|
||||
}, {
|
||||
message: "wrapped annotated error",
|
||||
generator: func() error {
|
||||
err := errors.Errorf("first error")
|
||||
err = errors.Annotatef(err, "annotated")
|
||||
return errors.Wrap(err, fmt.Errorf("detailed error"))
|
||||
},
|
||||
expected: "detailed error",
|
||||
}, {
|
||||
message: "annotated wrapped error",
|
||||
generator: func() error {
|
||||
err := errors.Errorf("first error")
|
||||
err = errors.Wrap(err, fmt.Errorf("detailed error"))
|
||||
return errors.Annotatef(err, "annotated")
|
||||
},
|
||||
expected: "annotated: detailed error",
|
||||
}, {
|
||||
message: "traced, and annotated",
|
||||
generator: func() error {
|
||||
err := errors.New("first error")
|
||||
err = errors.Trace(err)
|
||||
err = errors.Annotate(err, "some context")
|
||||
err = errors.Trace(err)
|
||||
err = errors.Annotate(err, "more context")
|
||||
return errors.Trace(err)
|
||||
},
|
||||
expected: "more context: some context: first error",
|
||||
}, {
|
||||
message: "traced, and annotated, masked and annotated",
|
||||
generator: func() error {
|
||||
err := errors.New("first error")
|
||||
err = errors.Trace(err)
|
||||
err = errors.Annotate(err, "some context")
|
||||
err = errors.Maskf(err, "masked")
|
||||
err = errors.Annotate(err, "more context")
|
||||
return errors.Trace(err)
|
||||
},
|
||||
expected: "more context: masked: some context: first error",
|
||||
},
|
||||
} {
|
||||
c.Logf("%v: %s", i, test.message)
|
||||
err := test.generator()
|
||||
ok := c.Check(err.Error(), gc.Equals, test.expected)
|
||||
if !ok {
|
||||
c.Logf("%#v", test.generator())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type embed struct {
|
||||
errors.Err
|
||||
}
|
||||
|
||||
func newEmbed(format string, args ...interface{}) *embed {
|
||||
err := &embed{errors.NewErr(format, args...)}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
func (*errorsSuite) TestNewErr(c *gc.C) {
|
||||
if runtime.Compiler == "gccgo" {
|
||||
c.Skip("gccgo can't determine the location")
|
||||
}
|
||||
err := newEmbed("testing %d", 42) //err embedErr
|
||||
c.Assert(err.Error(), gc.Equals, "testing 42")
|
||||
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["embedErr"].String())
|
||||
}
|
||||
|
||||
func newEmbedWithCause(other error, format string, args ...interface{}) *embed {
|
||||
err := &embed{errors.NewErrWithCause(other, format, args...)}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
func (*errorsSuite) TestNewErrWithCause(c *gc.C) {
|
||||
if runtime.Compiler == "gccgo" {
|
||||
c.Skip("gccgo can't determine the location")
|
||||
}
|
||||
causeErr := fmt.Errorf("external error")
|
||||
err := newEmbedWithCause(causeErr, "testing %d", 43) //err embedCause
|
||||
c.Assert(err.Error(), gc.Equals, "testing 43: external error")
|
||||
c.Assert(errors.Cause(err), gc.Equals, causeErr)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["embedCause"].String())
|
||||
}
|
||||
|
||||
var _ error = (*embed)(nil)
|
||||
|
||||
// This is an uncomparable error type, as it is a struct that supports the
|
||||
// error interface (as opposed to a pointer type).
|
||||
type error_ struct {
|
||||
info string
|
||||
slice []string
|
||||
}
|
||||
|
||||
// Create a non-comparable error
|
||||
func newNonComparableError(message string) error {
|
||||
return error_{info: message}
|
||||
}
|
||||
|
||||
func (e error_) Error() string {
|
||||
return e.info
|
||||
}
|
||||
|
||||
func newError(message string) error {
|
||||
return testError{message}
|
||||
}
|
||||
|
||||
// The testError is a value type error for ease of seeing results
|
||||
// when the test fails.
|
||||
type testError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
func (e testError) Error() string {
|
||||
return e.message
|
||||
}
|
309
vendor/github.com/juju/errors/errortypes.go
generated
vendored
Normal file
309
vendor/github.com/juju/errors/errortypes.go
generated
vendored
Normal file
|
@ -0,0 +1,309 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// wrap is a helper to construct an *wrapper.
|
||||
func wrap(err error, format, suffix string, args ...interface{}) Err {
|
||||
newErr := Err{
|
||||
message: fmt.Sprintf(format+suffix, args...),
|
||||
previous: err,
|
||||
}
|
||||
newErr.SetLocation(2)
|
||||
return newErr
|
||||
}
|
||||
|
||||
// notFound represents an error when something has not been found.
|
||||
type notFound struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// NotFoundf returns an error which satisfies IsNotFound().
|
||||
func NotFoundf(format string, args ...interface{}) error {
|
||||
return ¬Found{wrap(nil, format, " not found", args...)}
|
||||
}
|
||||
|
||||
// NewNotFound returns an error which wraps err that satisfies
|
||||
// IsNotFound().
|
||||
func NewNotFound(err error, msg string) error {
|
||||
return ¬Found{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsNotFound reports whether err was created with NotFoundf() or
|
||||
// NewNotFound().
|
||||
func IsNotFound(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*notFound)
|
||||
return ok
|
||||
}
|
||||
|
||||
// userNotFound represents an error when an inexistent user is looked up.
|
||||
type userNotFound struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// UserNotFoundf returns an error which satisfies IsUserNotFound().
|
||||
func UserNotFoundf(format string, args ...interface{}) error {
|
||||
return &userNotFound{wrap(nil, format, " user not found", args...)}
|
||||
}
|
||||
|
||||
// NewUserNotFound returns an error which wraps err and satisfies
|
||||
// IsUserNotFound().
|
||||
func NewUserNotFound(err error, msg string) error {
|
||||
return &userNotFound{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsUserNotFound reports whether err was created with UserNotFoundf() or
|
||||
// NewUserNotFound().
|
||||
func IsUserNotFound(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*userNotFound)
|
||||
return ok
|
||||
}
|
||||
|
||||
// unauthorized represents an error when an operation is unauthorized.
|
||||
type unauthorized struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// Unauthorizedf returns an error which satisfies IsUnauthorized().
|
||||
func Unauthorizedf(format string, args ...interface{}) error {
|
||||
return &unauthorized{wrap(nil, format, "", args...)}
|
||||
}
|
||||
|
||||
// NewUnauthorized returns an error which wraps err and satisfies
|
||||
// IsUnauthorized().
|
||||
func NewUnauthorized(err error, msg string) error {
|
||||
return &unauthorized{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsUnauthorized reports whether err was created with Unauthorizedf() or
|
||||
// NewUnauthorized().
|
||||
func IsUnauthorized(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*unauthorized)
|
||||
return ok
|
||||
}
|
||||
|
||||
// notImplemented represents an error when something is not
|
||||
// implemented.
|
||||
type notImplemented struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// NotImplementedf returns an error which satisfies IsNotImplemented().
|
||||
func NotImplementedf(format string, args ...interface{}) error {
|
||||
return ¬Implemented{wrap(nil, format, " not implemented", args...)}
|
||||
}
|
||||
|
||||
// NewNotImplemented returns an error which wraps err and satisfies
|
||||
// IsNotImplemented().
|
||||
func NewNotImplemented(err error, msg string) error {
|
||||
return ¬Implemented{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsNotImplemented reports whether err was created with
|
||||
// NotImplementedf() or NewNotImplemented().
|
||||
func IsNotImplemented(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*notImplemented)
|
||||
return ok
|
||||
}
|
||||
|
||||
// alreadyExists represents and error when something already exists.
|
||||
type alreadyExists struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// AlreadyExistsf returns an error which satisfies IsAlreadyExists().
|
||||
func AlreadyExistsf(format string, args ...interface{}) error {
|
||||
return &alreadyExists{wrap(nil, format, " already exists", args...)}
|
||||
}
|
||||
|
||||
// NewAlreadyExists returns an error which wraps err and satisfies
|
||||
// IsAlreadyExists().
|
||||
func NewAlreadyExists(err error, msg string) error {
|
||||
return &alreadyExists{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsAlreadyExists reports whether the error was created with
|
||||
// AlreadyExistsf() or NewAlreadyExists().
|
||||
func IsAlreadyExists(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*alreadyExists)
|
||||
return ok
|
||||
}
|
||||
|
||||
// notSupported represents an error when something is not supported.
|
||||
type notSupported struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// NotSupportedf returns an error which satisfies IsNotSupported().
|
||||
func NotSupportedf(format string, args ...interface{}) error {
|
||||
return ¬Supported{wrap(nil, format, " not supported", args...)}
|
||||
}
|
||||
|
||||
// NewNotSupported returns an error which wraps err and satisfies
|
||||
// IsNotSupported().
|
||||
func NewNotSupported(err error, msg string) error {
|
||||
return ¬Supported{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsNotSupported reports whether the error was created with
|
||||
// NotSupportedf() or NewNotSupported().
|
||||
func IsNotSupported(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*notSupported)
|
||||
return ok
|
||||
}
|
||||
|
||||
// notValid represents an error when something is not valid.
|
||||
type notValid struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// NotValidf returns an error which satisfies IsNotValid().
|
||||
func NotValidf(format string, args ...interface{}) error {
|
||||
return ¬Valid{wrap(nil, format, " not valid", args...)}
|
||||
}
|
||||
|
||||
// NewNotValid returns an error which wraps err and satisfies IsNotValid().
|
||||
func NewNotValid(err error, msg string) error {
|
||||
return ¬Valid{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsNotValid reports whether the error was created with NotValidf() or
|
||||
// NewNotValid().
|
||||
func IsNotValid(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*notValid)
|
||||
return ok
|
||||
}
|
||||
|
||||
// notProvisioned represents an error when something is not yet provisioned.
|
||||
type notProvisioned struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// NotProvisionedf returns an error which satisfies IsNotProvisioned().
|
||||
func NotProvisionedf(format string, args ...interface{}) error {
|
||||
return ¬Provisioned{wrap(nil, format, " not provisioned", args...)}
|
||||
}
|
||||
|
||||
// NewNotProvisioned returns an error which wraps err that satisfies
|
||||
// IsNotProvisioned().
|
||||
func NewNotProvisioned(err error, msg string) error {
|
||||
return ¬Provisioned{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsNotProvisioned reports whether err was created with NotProvisionedf() or
|
||||
// NewNotProvisioned().
|
||||
func IsNotProvisioned(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*notProvisioned)
|
||||
return ok
|
||||
}
|
||||
|
||||
// notAssigned represents an error when something is not yet assigned to
|
||||
// something else.
|
||||
type notAssigned struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// NotAssignedf returns an error which satisfies IsNotAssigned().
|
||||
func NotAssignedf(format string, args ...interface{}) error {
|
||||
return ¬Assigned{wrap(nil, format, " not assigned", args...)}
|
||||
}
|
||||
|
||||
// NewNotAssigned returns an error which wraps err that satisfies
|
||||
// IsNotAssigned().
|
||||
func NewNotAssigned(err error, msg string) error {
|
||||
return ¬Assigned{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsNotAssigned reports whether err was created with NotAssignedf() or
|
||||
// NewNotAssigned().
|
||||
func IsNotAssigned(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*notAssigned)
|
||||
return ok
|
||||
}
|
||||
|
||||
// badRequest represents an error when a request has bad parameters.
|
||||
type badRequest struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// BadRequestf returns an error which satisfies IsBadRequest().
|
||||
func BadRequestf(format string, args ...interface{}) error {
|
||||
return &badRequest{wrap(nil, format, "", args...)}
|
||||
}
|
||||
|
||||
// NewBadRequest returns an error which wraps err that satisfies
|
||||
// IsBadRequest().
|
||||
func NewBadRequest(err error, msg string) error {
|
||||
return &badRequest{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsBadRequest reports whether err was created with BadRequestf() or
|
||||
// NewBadRequest().
|
||||
func IsBadRequest(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*badRequest)
|
||||
return ok
|
||||
}
|
||||
|
||||
// methodNotAllowed represents an error when an HTTP request
|
||||
// is made with an inappropriate method.
|
||||
type methodNotAllowed struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// MethodNotAllowedf returns an error which satisfies IsMethodNotAllowed().
|
||||
func MethodNotAllowedf(format string, args ...interface{}) error {
|
||||
return &methodNotAllowed{wrap(nil, format, "", args...)}
|
||||
}
|
||||
|
||||
// NewMethodNotAllowed returns an error which wraps err that satisfies
|
||||
// IsMethodNotAllowed().
|
||||
func NewMethodNotAllowed(err error, msg string) error {
|
||||
return &methodNotAllowed{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsMethodNotAllowed reports whether err was created with MethodNotAllowedf() or
|
||||
// NewMethodNotAllowed().
|
||||
func IsMethodNotAllowed(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*methodNotAllowed)
|
||||
return ok
|
||||
}
|
||||
|
||||
// forbidden represents an error when a request cannot be completed because of
|
||||
// missing privileges
|
||||
type forbidden struct {
|
||||
Err
|
||||
}
|
||||
|
||||
// Forbiddenf returns an error which satistifes IsForbidden()
|
||||
func Forbiddenf(format string, args ...interface{}) error {
|
||||
return &forbidden{wrap(nil, format, "", args...)}
|
||||
}
|
||||
|
||||
// NewForbidden returns an error which wraps err that satisfies
|
||||
// IsForbidden().
|
||||
func NewForbidden(err error, msg string) error {
|
||||
return &forbidden{wrap(err, msg, "")}
|
||||
}
|
||||
|
||||
// IsForbidden reports whether err was created with Forbiddenf() or
|
||||
// NewForbidden().
|
||||
func IsForbidden(err error) bool {
|
||||
err = Cause(err)
|
||||
_, ok := err.(*forbidden)
|
||||
return ok
|
||||
}
|
174
vendor/github.com/juju/errors/errortypes_test.go
generated
vendored
Normal file
174
vendor/github.com/juju/errors/errortypes_test.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
// Copyright 2013, 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors_test
|
||||
|
||||
import (
|
||||
stderrors "errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
||||
"github.com/juju/errors"
|
||||
jc "github.com/juju/testing/checkers"
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
// errorInfo holds information about a single error type: a satisfier
|
||||
// function, wrapping and variable arguments constructors and message
|
||||
// suffix.
|
||||
type errorInfo struct {
|
||||
satisfier func(error) bool
|
||||
argsConstructor func(string, ...interface{}) error
|
||||
wrapConstructor func(error, string) error
|
||||
suffix string
|
||||
}
|
||||
|
||||
// allErrors holds information for all defined errors. When adding new
|
||||
// errors, add them here as well to include them in tests.
|
||||
var allErrors = []*errorInfo{
|
||||
{errors.IsNotFound, errors.NotFoundf, errors.NewNotFound, " not found"},
|
||||
{errors.IsUserNotFound, errors.UserNotFoundf, errors.NewUserNotFound, " user not found"},
|
||||
{errors.IsUnauthorized, errors.Unauthorizedf, errors.NewUnauthorized, ""},
|
||||
{errors.IsNotImplemented, errors.NotImplementedf, errors.NewNotImplemented, " not implemented"},
|
||||
{errors.IsAlreadyExists, errors.AlreadyExistsf, errors.NewAlreadyExists, " already exists"},
|
||||
{errors.IsNotSupported, errors.NotSupportedf, errors.NewNotSupported, " not supported"},
|
||||
{errors.IsNotValid, errors.NotValidf, errors.NewNotValid, " not valid"},
|
||||
{errors.IsNotProvisioned, errors.NotProvisionedf, errors.NewNotProvisioned, " not provisioned"},
|
||||
{errors.IsNotAssigned, errors.NotAssignedf, errors.NewNotAssigned, " not assigned"},
|
||||
{errors.IsMethodNotAllowed, errors.MethodNotAllowedf, errors.NewMethodNotAllowed, ""},
|
||||
{errors.IsBadRequest, errors.BadRequestf, errors.NewBadRequest, ""},
|
||||
{errors.IsForbidden, errors.Forbiddenf, errors.NewForbidden, ""},
|
||||
}
|
||||
|
||||
type errorTypeSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&errorTypeSuite{})
|
||||
|
||||
func (t *errorInfo) satisfierName() string {
|
||||
value := reflect.ValueOf(t.satisfier)
|
||||
f := runtime.FuncForPC(value.Pointer())
|
||||
return f.Name()
|
||||
}
|
||||
|
||||
func (t *errorInfo) equal(t0 *errorInfo) bool {
|
||||
if t0 == nil {
|
||||
return false
|
||||
}
|
||||
return t.satisfierName() == t0.satisfierName()
|
||||
}
|
||||
|
||||
type errorTest struct {
|
||||
err error
|
||||
message string
|
||||
errInfo *errorInfo
|
||||
}
|
||||
|
||||
func deferredAnnotatef(err error, format string, args ...interface{}) error {
|
||||
errors.DeferredAnnotatef(&err, format, args...)
|
||||
return err
|
||||
}
|
||||
|
||||
func mustSatisfy(c *gc.C, err error, errInfo *errorInfo) {
|
||||
if errInfo != nil {
|
||||
msg := fmt.Sprintf("%#v must satisfy %v", err, errInfo.satisfierName())
|
||||
c.Check(err, jc.Satisfies, errInfo.satisfier, gc.Commentf(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func mustNotSatisfy(c *gc.C, err error, errInfo *errorInfo) {
|
||||
if errInfo != nil {
|
||||
msg := fmt.Sprintf("%#v must not satisfy %v", err, errInfo.satisfierName())
|
||||
c.Check(err, gc.Not(jc.Satisfies), errInfo.satisfier, gc.Commentf(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func checkErrorMatches(c *gc.C, err error, message string, errInfo *errorInfo) {
|
||||
if message == "<nil>" {
|
||||
c.Check(err, gc.IsNil)
|
||||
c.Check(errInfo, gc.IsNil)
|
||||
} else {
|
||||
c.Check(err, gc.ErrorMatches, message)
|
||||
}
|
||||
}
|
||||
|
||||
func runErrorTests(c *gc.C, errorTests []errorTest, checkMustSatisfy bool) {
|
||||
for i, t := range errorTests {
|
||||
c.Logf("test %d: %T: %v", i, t.err, t.err)
|
||||
checkErrorMatches(c, t.err, t.message, t.errInfo)
|
||||
if checkMustSatisfy {
|
||||
mustSatisfy(c, t.err, t.errInfo)
|
||||
}
|
||||
|
||||
// Check all other satisfiers to make sure none match.
|
||||
for _, otherErrInfo := range allErrors {
|
||||
if checkMustSatisfy && otherErrInfo.equal(t.errInfo) {
|
||||
continue
|
||||
}
|
||||
mustNotSatisfy(c, t.err, otherErrInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (*errorTypeSuite) TestDeferredAnnotatef(c *gc.C) {
|
||||
// Ensure DeferredAnnotatef annotates the errors.
|
||||
errorTests := []errorTest{}
|
||||
for _, errInfo := range allErrors {
|
||||
errorTests = append(errorTests, []errorTest{{
|
||||
deferredAnnotatef(nil, "comment"),
|
||||
"<nil>",
|
||||
nil,
|
||||
}, {
|
||||
deferredAnnotatef(stderrors.New("blast"), "comment"),
|
||||
"comment: blast",
|
||||
nil,
|
||||
}, {
|
||||
deferredAnnotatef(errInfo.argsConstructor("foo %d", 42), "comment %d", 69),
|
||||
"comment 69: foo 42" + errInfo.suffix,
|
||||
errInfo,
|
||||
}, {
|
||||
deferredAnnotatef(errInfo.argsConstructor(""), "comment"),
|
||||
"comment: " + errInfo.suffix,
|
||||
errInfo,
|
||||
}, {
|
||||
deferredAnnotatef(errInfo.wrapConstructor(stderrors.New("pow!"), "woo"), "comment"),
|
||||
"comment: woo: pow!",
|
||||
errInfo,
|
||||
}}...)
|
||||
}
|
||||
|
||||
runErrorTests(c, errorTests, true)
|
||||
}
|
||||
|
||||
func (*errorTypeSuite) TestAllErrors(c *gc.C) {
|
||||
errorTests := []errorTest{}
|
||||
for _, errInfo := range allErrors {
|
||||
errorTests = append(errorTests, []errorTest{{
|
||||
nil,
|
||||
"<nil>",
|
||||
nil,
|
||||
}, {
|
||||
errInfo.argsConstructor("foo %d", 42),
|
||||
"foo 42" + errInfo.suffix,
|
||||
errInfo,
|
||||
}, {
|
||||
errInfo.argsConstructor(""),
|
||||
errInfo.suffix,
|
||||
errInfo,
|
||||
}, {
|
||||
errInfo.wrapConstructor(stderrors.New("pow!"), "prefix"),
|
||||
"prefix: pow!",
|
||||
errInfo,
|
||||
}, {
|
||||
errInfo.wrapConstructor(stderrors.New("pow!"), ""),
|
||||
"pow!",
|
||||
errInfo,
|
||||
}, {
|
||||
errInfo.wrapConstructor(nil, "prefix"),
|
||||
"prefix",
|
||||
errInfo,
|
||||
}}...)
|
||||
}
|
||||
|
||||
runErrorTests(c, errorTests, true)
|
||||
}
|
23
vendor/github.com/juju/errors/example_test.go
generated
vendored
Normal file
23
vendor/github.com/juju/errors/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2013, 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
func ExampleTrace() {
|
||||
var err1 error = fmt.Errorf("something wicked this way comes")
|
||||
var err2 error = nil
|
||||
|
||||
// Tracing a non nil error will return an error
|
||||
fmt.Println(errors.Trace(err1))
|
||||
// Tracing nil will return nil
|
||||
fmt.Println(errors.Trace(err2))
|
||||
|
||||
// Output: something wicked this way comes
|
||||
// <nil>
|
||||
}
|
12
vendor/github.com/juju/errors/export_test.go
generated
vendored
Normal file
12
vendor/github.com/juju/errors/export_test.go
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2013, 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors
|
||||
|
||||
// Since variables are declared before the init block, in order to get the goPath
|
||||
// we need to return it rather than just reference it.
|
||||
func GoPath() string {
|
||||
return goPath
|
||||
}
|
||||
|
||||
var TrimGoPath = trimGoPath
|
330
vendor/github.com/juju/errors/functions.go
generated
vendored
Normal file
330
vendor/github.com/juju/errors/functions.go
generated
vendored
Normal file
|
@ -0,0 +1,330 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// New is a drop in replacement for the standard library errors module that records
|
||||
// the location that the error is created.
|
||||
//
|
||||
// For example:
|
||||
// return errors.New("validation failed")
|
||||
//
|
||||
func New(message string) error {
|
||||
err := &Err{message: message}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Errorf creates a new annotated error and records the location that the
|
||||
// error is created. This should be a drop in replacement for fmt.Errorf.
|
||||
//
|
||||
// For example:
|
||||
// return errors.Errorf("validation failed: %s", message)
|
||||
//
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
err := &Err{message: fmt.Sprintf(format, args...)}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Trace adds the location of the Trace call to the stack. The Cause of the
|
||||
// resulting error is the same as the error parameter. If the other error is
|
||||
// nil, the result will be nil.
|
||||
//
|
||||
// For example:
|
||||
// if err := SomeFunc(); err != nil {
|
||||
// return errors.Trace(err)
|
||||
// }
|
||||
//
|
||||
func Trace(other error) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
err := &Err{previous: other, cause: Cause(other)}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Annotate is used to add extra context to an existing error. The location of
|
||||
// the Annotate call is recorded with the annotations. The file, line and
|
||||
// function are also recorded.
|
||||
//
|
||||
// For example:
|
||||
// if err := SomeFunc(); err != nil {
|
||||
// return errors.Annotate(err, "failed to frombulate")
|
||||
// }
|
||||
//
|
||||
func Annotate(other error, message string) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
err := &Err{
|
||||
previous: other,
|
||||
cause: Cause(other),
|
||||
message: message,
|
||||
}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Annotatef is used to add extra context to an existing error. The location of
|
||||
// the Annotate call is recorded with the annotations. The file, line and
|
||||
// function are also recorded.
|
||||
//
|
||||
// For example:
|
||||
// if err := SomeFunc(); err != nil {
|
||||
// return errors.Annotatef(err, "failed to frombulate the %s", arg)
|
||||
// }
|
||||
//
|
||||
func Annotatef(other error, format string, args ...interface{}) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
err := &Err{
|
||||
previous: other,
|
||||
cause: Cause(other),
|
||||
message: fmt.Sprintf(format, args...),
|
||||
}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeferredAnnotatef annotates the given error (when it is not nil) with the given
|
||||
// format string and arguments (like fmt.Sprintf). If *err is nil, DeferredAnnotatef
|
||||
// does nothing. This method is used in a defer statement in order to annotate any
|
||||
// resulting error with the same message.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// defer DeferredAnnotatef(&err, "failed to frombulate the %s", arg)
|
||||
//
|
||||
func DeferredAnnotatef(err *error, format string, args ...interface{}) {
|
||||
if *err == nil {
|
||||
return
|
||||
}
|
||||
newErr := &Err{
|
||||
message: fmt.Sprintf(format, args...),
|
||||
cause: Cause(*err),
|
||||
previous: *err,
|
||||
}
|
||||
newErr.SetLocation(1)
|
||||
*err = newErr
|
||||
}
|
||||
|
||||
// Wrap changes the Cause of the error. The location of the Wrap call is also
|
||||
// stored in the error stack.
|
||||
//
|
||||
// For example:
|
||||
// if err := SomeFunc(); err != nil {
|
||||
// newErr := &packageError{"more context", private_value}
|
||||
// return errors.Wrap(err, newErr)
|
||||
// }
|
||||
//
|
||||
func Wrap(other, newDescriptive error) error {
|
||||
err := &Err{
|
||||
previous: other,
|
||||
cause: newDescriptive,
|
||||
}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Wrapf changes the Cause of the error, and adds an annotation. The location
|
||||
// of the Wrap call is also stored in the error stack.
|
||||
//
|
||||
// For example:
|
||||
// if err := SomeFunc(); err != nil {
|
||||
// return errors.Wrapf(err, simpleErrorType, "invalid value %q", value)
|
||||
// }
|
||||
//
|
||||
func Wrapf(other, newDescriptive error, format string, args ...interface{}) error {
|
||||
err := &Err{
|
||||
message: fmt.Sprintf(format, args...),
|
||||
previous: other,
|
||||
cause: newDescriptive,
|
||||
}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Mask masks the given error with the given format string and arguments (like
|
||||
// fmt.Sprintf), returning a new error that maintains the error stack, but
|
||||
// hides the underlying error type. The error string still contains the full
|
||||
// annotations. If you want to hide the annotations, call Wrap.
|
||||
func Maskf(other error, format string, args ...interface{}) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
err := &Err{
|
||||
message: fmt.Sprintf(format, args...),
|
||||
previous: other,
|
||||
}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Mask hides the underlying error type, and records the location of the masking.
|
||||
func Mask(other error) error {
|
||||
if other == nil {
|
||||
return nil
|
||||
}
|
||||
err := &Err{
|
||||
previous: other,
|
||||
}
|
||||
err.SetLocation(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// Cause returns the cause of the given error. This will be either the
|
||||
// original error, or the result of a Wrap or Mask call.
|
||||
//
|
||||
// Cause is the usual way to diagnose errors that may have been wrapped by
|
||||
// the other errors functions.
|
||||
func Cause(err error) error {
|
||||
var diag error
|
||||
if err, ok := err.(causer); ok {
|
||||
diag = err.Cause()
|
||||
}
|
||||
if diag != nil {
|
||||
return diag
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
type wrapper interface {
|
||||
// Message returns the top level error message,
|
||||
// not including the message from the Previous
|
||||
// error.
|
||||
Message() string
|
||||
|
||||
// Underlying returns the Previous error, or nil
|
||||
// if there is none.
|
||||
Underlying() error
|
||||
}
|
||||
|
||||
type locationer interface {
|
||||
Location() (string, int)
|
||||
}
|
||||
|
||||
var (
|
||||
_ wrapper = (*Err)(nil)
|
||||
_ locationer = (*Err)(nil)
|
||||
_ causer = (*Err)(nil)
|
||||
)
|
||||
|
||||
// Details returns information about the stack of errors wrapped by err, in
|
||||
// the format:
|
||||
//
|
||||
// [{filename:99: error one} {otherfile:55: cause of error one}]
|
||||
//
|
||||
// This is a terse alternative to ErrorStack as it returns a single line.
|
||||
func Details(err error) string {
|
||||
if err == nil {
|
||||
return "[]"
|
||||
}
|
||||
var s []byte
|
||||
s = append(s, '[')
|
||||
for {
|
||||
s = append(s, '{')
|
||||
if err, ok := err.(locationer); ok {
|
||||
file, line := err.Location()
|
||||
if file != "" {
|
||||
s = append(s, fmt.Sprintf("%s:%d", file, line)...)
|
||||
s = append(s, ": "...)
|
||||
}
|
||||
}
|
||||
if cerr, ok := err.(wrapper); ok {
|
||||
s = append(s, cerr.Message()...)
|
||||
err = cerr.Underlying()
|
||||
} else {
|
||||
s = append(s, err.Error()...)
|
||||
err = nil
|
||||
}
|
||||
s = append(s, '}')
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
s = append(s, ' ')
|
||||
}
|
||||
s = append(s, ']')
|
||||
return string(s)
|
||||
}
|
||||
|
||||
// ErrorStack returns a string representation of the annotated error. If the
|
||||
// error passed as the parameter is not an annotated error, the result is
|
||||
// simply the result of the Error() method on that error.
|
||||
//
|
||||
// If the error is an annotated error, a multi-line string is returned where
|
||||
// each line represents one entry in the annotation stack. The full filename
|
||||
// from the call stack is used in the output.
|
||||
//
|
||||
// first error
|
||||
// github.com/juju/errors/annotation_test.go:193:
|
||||
// github.com/juju/errors/annotation_test.go:194: annotation
|
||||
// github.com/juju/errors/annotation_test.go:195:
|
||||
// github.com/juju/errors/annotation_test.go:196: more context
|
||||
// github.com/juju/errors/annotation_test.go:197:
|
||||
func ErrorStack(err error) string {
|
||||
return strings.Join(errorStack(err), "\n")
|
||||
}
|
||||
|
||||
func errorStack(err error) []string {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We want the first error first
|
||||
var lines []string
|
||||
for {
|
||||
var buff []byte
|
||||
if err, ok := err.(locationer); ok {
|
||||
file, line := err.Location()
|
||||
// Strip off the leading GOPATH/src path elements.
|
||||
file = trimGoPath(file)
|
||||
if file != "" {
|
||||
buff = append(buff, fmt.Sprintf("%s:%d", file, line)...)
|
||||
buff = append(buff, ": "...)
|
||||
}
|
||||
}
|
||||
if cerr, ok := err.(wrapper); ok {
|
||||
message := cerr.Message()
|
||||
buff = append(buff, message...)
|
||||
// If there is a cause for this error, and it is different to the cause
|
||||
// of the underlying error, then output the error string in the stack trace.
|
||||
var cause error
|
||||
if err1, ok := err.(causer); ok {
|
||||
cause = err1.Cause()
|
||||
}
|
||||
err = cerr.Underlying()
|
||||
if cause != nil && !sameError(Cause(err), cause) {
|
||||
if message != "" {
|
||||
buff = append(buff, ": "...)
|
||||
}
|
||||
buff = append(buff, cause.Error()...)
|
||||
}
|
||||
} else {
|
||||
buff = append(buff, err.Error()...)
|
||||
err = nil
|
||||
}
|
||||
lines = append(lines, string(buff))
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
// reverse the lines to get the original error, which was at the end of
|
||||
// the list, back to the start.
|
||||
var result []string
|
||||
for i := len(lines); i > 0; i-- {
|
||||
result = append(result, lines[i-1])
|
||||
}
|
||||
return result
|
||||
}
|
305
vendor/github.com/juju/errors/functions_test.go
generated
vendored
Normal file
305
vendor/github.com/juju/errors/functions_test.go
generated
vendored
Normal file
|
@ -0,0 +1,305 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
jc "github.com/juju/testing/checkers"
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type functionSuite struct {
|
||||
}
|
||||
|
||||
var _ = gc.Suite(&functionSuite{})
|
||||
|
||||
func (*functionSuite) TestNew(c *gc.C) {
|
||||
err := errors.New("testing") //err newTest
|
||||
c.Assert(err.Error(), gc.Equals, "testing")
|
||||
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["newTest"].String())
|
||||
}
|
||||
|
||||
func (*functionSuite) TestErrorf(c *gc.C) {
|
||||
err := errors.Errorf("testing %d", 42) //err errorfTest
|
||||
c.Assert(err.Error(), gc.Equals, "testing 42")
|
||||
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["errorfTest"].String())
|
||||
}
|
||||
|
||||
func (*functionSuite) TestTrace(c *gc.C) {
|
||||
first := errors.New("first")
|
||||
err := errors.Trace(first) //err traceTest
|
||||
c.Assert(err.Error(), gc.Equals, "first")
|
||||
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["traceTest"].String())
|
||||
|
||||
c.Assert(errors.Trace(nil), gc.IsNil)
|
||||
}
|
||||
|
||||
func (*functionSuite) TestAnnotate(c *gc.C) {
|
||||
first := errors.New("first")
|
||||
err := errors.Annotate(first, "annotation") //err annotateTest
|
||||
c.Assert(err.Error(), gc.Equals, "annotation: first")
|
||||
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotateTest"].String())
|
||||
|
||||
c.Assert(errors.Annotate(nil, "annotate"), gc.IsNil)
|
||||
}
|
||||
|
||||
func (*functionSuite) TestAnnotatef(c *gc.C) {
|
||||
first := errors.New("first")
|
||||
err := errors.Annotatef(first, "annotation %d", 2) //err annotatefTest
|
||||
c.Assert(err.Error(), gc.Equals, "annotation 2: first")
|
||||
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["annotatefTest"].String())
|
||||
|
||||
c.Assert(errors.Annotatef(nil, "annotate"), gc.IsNil)
|
||||
}
|
||||
|
||||
func (*functionSuite) TestDeferredAnnotatef(c *gc.C) {
|
||||
// NOTE: this test fails with gccgo
|
||||
if runtime.Compiler == "gccgo" {
|
||||
c.Skip("gccgo can't determine the location")
|
||||
}
|
||||
first := errors.New("first")
|
||||
test := func() (err error) {
|
||||
defer errors.DeferredAnnotatef(&err, "deferred %s", "annotate")
|
||||
return first //err deferredAnnotate
|
||||
}
|
||||
err := test()
|
||||
c.Assert(err.Error(), gc.Equals, "deferred annotate: first")
|
||||
c.Assert(errors.Cause(err), gc.Equals, first)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["deferredAnnotate"].String())
|
||||
|
||||
err = nil
|
||||
errors.DeferredAnnotatef(&err, "deferred %s", "annotate")
|
||||
c.Assert(err, gc.IsNil)
|
||||
}
|
||||
|
||||
func (*functionSuite) TestWrap(c *gc.C) {
|
||||
first := errors.New("first") //err wrapFirst
|
||||
detailed := errors.New("detailed")
|
||||
err := errors.Wrap(first, detailed) //err wrapTest
|
||||
c.Assert(err.Error(), gc.Equals, "detailed")
|
||||
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapFirst"].String())
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapTest"].String())
|
||||
}
|
||||
|
||||
func (*functionSuite) TestWrapOfNil(c *gc.C) {
|
||||
detailed := errors.New("detailed")
|
||||
err := errors.Wrap(nil, detailed) //err nilWrapTest
|
||||
c.Assert(err.Error(), gc.Equals, "detailed")
|
||||
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapTest"].String())
|
||||
}
|
||||
|
||||
func (*functionSuite) TestWrapf(c *gc.C) {
|
||||
first := errors.New("first") //err wrapfFirst
|
||||
detailed := errors.New("detailed")
|
||||
err := errors.Wrapf(first, detailed, "value %d", 42) //err wrapfTest
|
||||
c.Assert(err.Error(), gc.Equals, "value 42: detailed")
|
||||
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfFirst"].String())
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["wrapfTest"].String())
|
||||
}
|
||||
|
||||
func (*functionSuite) TestWrapfOfNil(c *gc.C) {
|
||||
detailed := errors.New("detailed")
|
||||
err := errors.Wrapf(nil, detailed, "value %d", 42) //err nilWrapfTest
|
||||
c.Assert(err.Error(), gc.Equals, "value 42: detailed")
|
||||
c.Assert(errors.Cause(err), gc.Equals, detailed)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["nilWrapfTest"].String())
|
||||
}
|
||||
|
||||
func (*functionSuite) TestMask(c *gc.C) {
|
||||
first := errors.New("first")
|
||||
err := errors.Mask(first) //err maskTest
|
||||
c.Assert(err.Error(), gc.Equals, "first")
|
||||
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskTest"].String())
|
||||
|
||||
c.Assert(errors.Mask(nil), gc.IsNil)
|
||||
}
|
||||
|
||||
func (*functionSuite) TestMaskf(c *gc.C) {
|
||||
first := errors.New("first")
|
||||
err := errors.Maskf(first, "masked %d", 42) //err maskfTest
|
||||
c.Assert(err.Error(), gc.Equals, "masked 42: first")
|
||||
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||
c.Assert(errors.Details(err), jc.Contains, tagToLocation["maskfTest"].String())
|
||||
|
||||
c.Assert(errors.Maskf(nil, "mask"), gc.IsNil)
|
||||
}
|
||||
|
||||
func (*functionSuite) TestCause(c *gc.C) {
|
||||
c.Assert(errors.Cause(nil), gc.IsNil)
|
||||
c.Assert(errors.Cause(someErr), gc.Equals, someErr)
|
||||
|
||||
fmtErr := fmt.Errorf("simple")
|
||||
c.Assert(errors.Cause(fmtErr), gc.Equals, fmtErr)
|
||||
|
||||
err := errors.Wrap(someErr, fmtErr)
|
||||
c.Assert(errors.Cause(err), gc.Equals, fmtErr)
|
||||
|
||||
err = errors.Annotate(err, "annotated")
|
||||
c.Assert(errors.Cause(err), gc.Equals, fmtErr)
|
||||
|
||||
err = errors.Maskf(err, "maksed")
|
||||
c.Assert(errors.Cause(err), gc.Equals, err)
|
||||
|
||||
// Look for a file that we know isn't there.
|
||||
dir := c.MkDir()
|
||||
_, err = os.Stat(filepath.Join(dir, "not-there"))
|
||||
c.Assert(os.IsNotExist(err), jc.IsTrue)
|
||||
|
||||
err = errors.Annotatef(err, "wrap it")
|
||||
// Now the error itself isn't a 'IsNotExist'.
|
||||
c.Assert(os.IsNotExist(err), jc.IsFalse)
|
||||
// However if we use the Check method, it is.
|
||||
c.Assert(os.IsNotExist(errors.Cause(err)), jc.IsTrue)
|
||||
}
|
||||
|
||||
func (s *functionSuite) TestDetails(c *gc.C) {
|
||||
if runtime.Compiler == "gccgo" {
|
||||
c.Skip("gccgo can't determine the location")
|
||||
}
|
||||
c.Assert(errors.Details(nil), gc.Equals, "[]")
|
||||
|
||||
otherErr := fmt.Errorf("other")
|
||||
checkDetails(c, otherErr, "[{other}]")
|
||||
|
||||
err0 := newEmbed("foo") //err TestStack#0
|
||||
checkDetails(c, err0, "[{$TestStack#0$: foo}]")
|
||||
|
||||
err1 := errors.Annotate(err0, "bar") //err TestStack#1
|
||||
checkDetails(c, err1, "[{$TestStack#1$: bar} {$TestStack#0$: foo}]")
|
||||
|
||||
err2 := errors.Trace(err1) //err TestStack#2
|
||||
checkDetails(c, err2, "[{$TestStack#2$: } {$TestStack#1$: bar} {$TestStack#0$: foo}]")
|
||||
}
|
||||
|
||||
type tracer interface {
|
||||
StackTrace() []string
|
||||
}
|
||||
|
||||
func (*functionSuite) TestErrorStack(c *gc.C) {
|
||||
for i, test := range []struct {
|
||||
message string
|
||||
generator func() error
|
||||
expected string
|
||||
tracer bool
|
||||
}{
|
||||
{
|
||||
message: "nil",
|
||||
generator: func() error {
|
||||
return nil
|
||||
},
|
||||
}, {
|
||||
message: "raw error",
|
||||
generator: func() error {
|
||||
return fmt.Errorf("raw")
|
||||
},
|
||||
expected: "raw",
|
||||
}, {
|
||||
message: "single error stack",
|
||||
generator: func() error {
|
||||
return errors.New("first error") //err single
|
||||
},
|
||||
expected: "$single$: first error",
|
||||
tracer: true,
|
||||
}, {
|
||||
message: "annotated error",
|
||||
generator: func() error {
|
||||
err := errors.New("first error") //err annotated-0
|
||||
return errors.Annotate(err, "annotation") //err annotated-1
|
||||
},
|
||||
expected: "" +
|
||||
"$annotated-0$: first error\n" +
|
||||
"$annotated-1$: annotation",
|
||||
tracer: true,
|
||||
}, {
|
||||
message: "wrapped error",
|
||||
generator: func() error {
|
||||
err := errors.New("first error") //err wrapped-0
|
||||
return errors.Wrap(err, newError("detailed error")) //err wrapped-1
|
||||
},
|
||||
expected: "" +
|
||||
"$wrapped-0$: first error\n" +
|
||||
"$wrapped-1$: detailed error",
|
||||
tracer: true,
|
||||
}, {
|
||||
message: "annotated wrapped error",
|
||||
generator: func() error {
|
||||
err := errors.Errorf("first error") //err ann-wrap-0
|
||||
err = errors.Wrap(err, fmt.Errorf("detailed error")) //err ann-wrap-1
|
||||
return errors.Annotatef(err, "annotated") //err ann-wrap-2
|
||||
},
|
||||
expected: "" +
|
||||
"$ann-wrap-0$: first error\n" +
|
||||
"$ann-wrap-1$: detailed error\n" +
|
||||
"$ann-wrap-2$: annotated",
|
||||
tracer: true,
|
||||
}, {
|
||||
message: "traced, and annotated",
|
||||
generator: func() error {
|
||||
err := errors.New("first error") //err stack-0
|
||||
err = errors.Trace(err) //err stack-1
|
||||
err = errors.Annotate(err, "some context") //err stack-2
|
||||
err = errors.Trace(err) //err stack-3
|
||||
err = errors.Annotate(err, "more context") //err stack-4
|
||||
return errors.Trace(err) //err stack-5
|
||||
},
|
||||
expected: "" +
|
||||
"$stack-0$: first error\n" +
|
||||
"$stack-1$: \n" +
|
||||
"$stack-2$: some context\n" +
|
||||
"$stack-3$: \n" +
|
||||
"$stack-4$: more context\n" +
|
||||
"$stack-5$: ",
|
||||
tracer: true,
|
||||
}, {
|
||||
message: "uncomparable, wrapped with a value error",
|
||||
generator: func() error {
|
||||
err := newNonComparableError("first error") //err mixed-0
|
||||
err = errors.Trace(err) //err mixed-1
|
||||
err = errors.Wrap(err, newError("value error")) //err mixed-2
|
||||
err = errors.Maskf(err, "masked") //err mixed-3
|
||||
err = errors.Annotate(err, "more context") //err mixed-4
|
||||
return errors.Trace(err) //err mixed-5
|
||||
},
|
||||
expected: "" +
|
||||
"first error\n" +
|
||||
"$mixed-1$: \n" +
|
||||
"$mixed-2$: value error\n" +
|
||||
"$mixed-3$: masked\n" +
|
||||
"$mixed-4$: more context\n" +
|
||||
"$mixed-5$: ",
|
||||
tracer: true,
|
||||
},
|
||||
} {
|
||||
c.Logf("%v: %s", i, test.message)
|
||||
err := test.generator()
|
||||
expected := replaceLocations(test.expected)
|
||||
stack := errors.ErrorStack(err)
|
||||
ok := c.Check(stack, gc.Equals, expected)
|
||||
if !ok {
|
||||
c.Logf("%#v", err)
|
||||
}
|
||||
tracer, ok := err.(tracer)
|
||||
c.Check(ok, gc.Equals, test.tracer)
|
||||
if ok {
|
||||
stackTrace := tracer.StackTrace()
|
||||
c.Check(stackTrace, gc.DeepEquals, strings.Split(stack, "\n"))
|
||||
}
|
||||
}
|
||||
}
|
95
vendor/github.com/juju/errors/package_test.go
generated
vendored
Normal file
95
vendor/github.com/juju/errors/package_test.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2013, 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
gc.TestingT(t)
|
||||
}
|
||||
|
||||
func checkDetails(c *gc.C, err error, details string) {
|
||||
c.Assert(err, gc.NotNil)
|
||||
expectedDetails := replaceLocations(details)
|
||||
c.Assert(errors.Details(err), gc.Equals, expectedDetails)
|
||||
}
|
||||
|
||||
func checkErr(c *gc.C, err, cause error, msg string, details string) {
|
||||
c.Assert(err, gc.NotNil)
|
||||
c.Assert(err.Error(), gc.Equals, msg)
|
||||
c.Assert(errors.Cause(err), gc.Equals, cause)
|
||||
expectedDetails := replaceLocations(details)
|
||||
c.Assert(errors.Details(err), gc.Equals, expectedDetails)
|
||||
}
|
||||
|
||||
func replaceLocations(line string) string {
|
||||
result := ""
|
||||
for {
|
||||
i := strings.Index(line, "$")
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
result += line[0:i]
|
||||
line = line[i+1:]
|
||||
i = strings.Index(line, "$")
|
||||
if i == -1 {
|
||||
panic("no second $")
|
||||
}
|
||||
result += location(line[0:i]).String()
|
||||
line = line[i+1:]
|
||||
}
|
||||
result += line
|
||||
return result
|
||||
}
|
||||
|
||||
func location(tag string) Location {
|
||||
loc, ok := tagToLocation[tag]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("tag %q not found", tag))
|
||||
}
|
||||
return loc
|
||||
}
|
||||
|
||||
type Location struct {
|
||||
file string
|
||||
line int
|
||||
}
|
||||
|
||||
func (loc Location) String() string {
|
||||
return fmt.Sprintf("%s:%d", loc.file, loc.line)
|
||||
}
|
||||
|
||||
var tagToLocation = make(map[string]Location)
|
||||
|
||||
func setLocationsForErrorTags(filename string) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
filename = "github.com/juju/errors/" + filename
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for i, line := range lines {
|
||||
if j := strings.Index(line, "//err "); j >= 0 {
|
||||
tag := line[j+len("//err "):]
|
||||
if _, found := tagToLocation[tag]; found {
|
||||
panic(fmt.Sprintf("tag %q already processed previously", tag))
|
||||
}
|
||||
tagToLocation[tag] = Location{file: filename, line: i + 1}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
setLocationsForErrorTags("error_test.go")
|
||||
setLocationsForErrorTags("functions_test.go")
|
||||
}
|
38
vendor/github.com/juju/errors/path.go
generated
vendored
Normal file
38
vendor/github.com/juju/errors/path.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2013, 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// prefixSize is used internally to trim the user specific path from the
|
||||
// front of the returned filenames from the runtime call stack.
|
||||
var prefixSize int
|
||||
|
||||
// goPath is the deduced path based on the location of this file as compiled.
|
||||
var goPath string
|
||||
|
||||
func init() {
|
||||
_, file, _, ok := runtime.Caller(0)
|
||||
if file == "?" {
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
// We know that the end of the file should be:
|
||||
// github.com/juju/errors/path.go
|
||||
size := len(file)
|
||||
suffix := len("github.com/juju/errors/path.go")
|
||||
goPath = file[:size-suffix]
|
||||
prefixSize = len(goPath)
|
||||
}
|
||||
}
|
||||
|
||||
func trimGoPath(filename string) string {
|
||||
if strings.HasPrefix(filename, goPath) {
|
||||
return filename[prefixSize:]
|
||||
}
|
||||
return filename
|
||||
}
|
29
vendor/github.com/juju/errors/path_test.go
generated
vendored
Normal file
29
vendor/github.com/juju/errors/path_test.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2013, 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package errors_test
|
||||
|
||||
import (
|
||||
"path"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/errors"
|
||||
)
|
||||
|
||||
type pathSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&pathSuite{})
|
||||
|
||||
func (*pathSuite) TestGoPathSet(c *gc.C) {
|
||||
c.Assert(errors.GoPath(), gc.Not(gc.Equals), "")
|
||||
}
|
||||
|
||||
func (*pathSuite) TestTrimGoPath(c *gc.C) {
|
||||
relativeImport := "github.com/foo/bar/baz.go"
|
||||
filename := path.Join(errors.GoPath(), relativeImport)
|
||||
c.Assert(errors.TrimGoPath(filename), gc.Equals, relativeImport)
|
||||
|
||||
absoluteImport := "/usr/share/foo/bar/baz.go"
|
||||
c.Assert(errors.TrimGoPath(absoluteImport), gc.Equals, absoluteImport)
|
||||
}
|
191
vendor/github.com/juju/loggo/LICENSE
generated
vendored
Normal file
191
vendor/github.com/juju/loggo/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
All files in this repository are licensed as follows. If you contribute
|
||||
to this repository, it is assumed that you license your contribution
|
||||
under the same license unless you state otherwise.
|
||||
|
||||
All files Copyright (C) 2015 Canonical Ltd. unless otherwise specified in the file.
|
||||
|
||||
This software is licensed under the LGPLv3, included below.
|
||||
|
||||
As a special exception to the GNU Lesser General Public License version 3
|
||||
("LGPL3"), the copyright holders of this Library give you permission to
|
||||
convey to a third party a Combined Work that links statically or dynamically
|
||||
to this Library without providing any Minimal Corresponding Source or
|
||||
Minimal Application Code as set out in 4d or providing the installation
|
||||
information set out in section 4e, provided that you comply with the other
|
||||
provisions of LGPL3 and provided that you meet, for the Application the
|
||||
terms and conditions of the license(s) which apply to the Application.
|
||||
|
||||
Except as stated in this special exception, the provisions of LGPL3 will
|
||||
continue to comply in full to this Library. If you modify this Library, you
|
||||
may apply this exception to your version of this Library, but you are not
|
||||
obliged to do so. If you do not wish to do so, delete this exception
|
||||
statement from your version. This exception does not (and cannot) modify any
|
||||
license terms which apply to the Application, with which you must still
|
||||
comply.
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
11
vendor/github.com/juju/loggo/Makefile
generated
vendored
Normal file
11
vendor/github.com/juju/loggo/Makefile
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
default: check
|
||||
|
||||
check:
|
||||
go test
|
||||
|
||||
docs:
|
||||
godoc2md github.com/juju/loggo > README.md
|
||||
sed -i 's|\[godoc-link-here\]|[![GoDoc](https://godoc.org/github.com/juju/loggo?status.svg)](https://godoc.org/github.com/juju/loggo)|' README.md
|
||||
|
||||
|
||||
.PHONY: default check docs
|
711
vendor/github.com/juju/loggo/README.md
generated
vendored
Normal file
711
vendor/github.com/juju/loggo/README.md
generated
vendored
Normal file
|
@ -0,0 +1,711 @@
|
|||
|
||||
# loggo
|
||||
import "github.com/juju/loggo"
|
||||
|
||||
[![GoDoc](https://godoc.org/github.com/juju/loggo?status.svg)](https://godoc.org/github.com/juju/loggo)
|
||||
|
||||
### Module level logging for Go
|
||||
This package provides an alternative to the standard library log package.
|
||||
|
||||
The actual logging functions never return errors. If you are logging
|
||||
something, you really don't want to be worried about the logging
|
||||
having trouble.
|
||||
|
||||
Modules have names that are defined by dotted strings.
|
||||
|
||||
|
||||
"first.second.third"
|
||||
|
||||
There is a root module that has the name `""`. Each module
|
||||
(except the root module) has a parent, identified by the part of
|
||||
the name without the last dotted value.
|
||||
* the parent of "first.second.third" is "first.second"
|
||||
* the parent of "first.second" is "first"
|
||||
* the parent of "first" is "" (the root module)
|
||||
|
||||
Each module can specify its own severity level. Logging calls that are of
|
||||
a lower severity than the module's effective severity level are not written
|
||||
out.
|
||||
|
||||
Loggers are created using the GetLogger function.
|
||||
|
||||
|
||||
logger := loggo.GetLogger("foo.bar")
|
||||
|
||||
By default there is one writer registered, which will write to Stderr,
|
||||
and the root module, which will only emit warnings and above.
|
||||
If you want to continue using the default
|
||||
logger, but have it emit all logging levels you need to do the following.
|
||||
|
||||
|
||||
writer, _, err := loggo.RemoveWriter("default")
|
||||
// err is non-nil if and only if the name isn't found.
|
||||
loggo.RegisterWriter("default", writer, loggo.TRACE)
|
||||
|
||||
|
||||
|
||||
|
||||
## Constants
|
||||
``` go
|
||||
const DefaultWriterName = "default"
|
||||
```
|
||||
DefaultWriterName is the name of the default writer for
|
||||
a Context.
|
||||
|
||||
|
||||
## Variables
|
||||
``` go
|
||||
var (
|
||||
// SeverityColor defines the colors for the levels output by the ColorWriter.
|
||||
SeverityColor = map[Level]*ansiterm.Context{
|
||||
TRACE: ansiterm.Foreground(ansiterm.Default),
|
||||
DEBUG: ansiterm.Foreground(ansiterm.Green),
|
||||
INFO: ansiterm.Foreground(ansiterm.BrightBlue),
|
||||
WARNING: ansiterm.Foreground(ansiterm.Yellow),
|
||||
ERROR: ansiterm.Foreground(ansiterm.BrightRed),
|
||||
CRITICAL: &ansiterm.Context{
|
||||
Foreground: ansiterm.White,
|
||||
Background: ansiterm.Red,
|
||||
},
|
||||
}
|
||||
// LocationColor defines the colors for the location output by the ColorWriter.
|
||||
LocationColor = ansiterm.Foreground(ansiterm.BrightBlue)
|
||||
)
|
||||
```
|
||||
``` go
|
||||
var TimeFormat = initTimeFormat()
|
||||
```
|
||||
TimeFormat is the time format used for the default writer.
|
||||
This can be set with the environment variable LOGGO_TIME_FORMAT.
|
||||
|
||||
|
||||
## func ConfigureLoggers
|
||||
``` go
|
||||
func ConfigureLoggers(specification string) error
|
||||
```
|
||||
ConfigureLoggers configures loggers according to the given string
|
||||
specification, which specifies a set of modules and their associated
|
||||
logging levels. Loggers are colon- or semicolon-separated; each
|
||||
module is specified as <modulename>=<level>. White space outside of
|
||||
module names and levels is ignored. The root module is specified
|
||||
with the name "<root>".
|
||||
|
||||
An example specification:
|
||||
|
||||
|
||||
`<root>=ERROR; foo.bar=WARNING`
|
||||
|
||||
|
||||
## func DefaultFormatter
|
||||
``` go
|
||||
func DefaultFormatter(entry Entry) string
|
||||
```
|
||||
DefaultFormatter returns the parameters separated by spaces except for
|
||||
filename and line which are separated by a colon. The timestamp is shown
|
||||
to second resolution in UTC. For example:
|
||||
|
||||
|
||||
2016-07-02 15:04:05
|
||||
|
||||
|
||||
## func LoggerInfo
|
||||
``` go
|
||||
func LoggerInfo() string
|
||||
```
|
||||
LoggerInfo returns information about the configured loggers and their
|
||||
logging levels. The information is returned in the format expected by
|
||||
ConfigureLoggers. Loggers with UNSPECIFIED level will not
|
||||
be included.
|
||||
|
||||
|
||||
## func RegisterWriter
|
||||
``` go
|
||||
func RegisterWriter(name string, writer Writer) error
|
||||
```
|
||||
RegisterWriter adds the writer to the list of writers in the DefaultContext
|
||||
that get notified when logging. If there is already a registered writer
|
||||
with that name, an error is returned.
|
||||
|
||||
|
||||
## func ResetLogging
|
||||
``` go
|
||||
func ResetLogging()
|
||||
```
|
||||
ResetLogging iterates through the known modules and sets the levels of all
|
||||
to UNSPECIFIED, except for <root> which is set to WARNING. The call also
|
||||
removes all writers in the DefaultContext and puts the original default
|
||||
writer back as the only writer.
|
||||
|
||||
|
||||
## func ResetWriters
|
||||
``` go
|
||||
func ResetWriters()
|
||||
```
|
||||
ResetWriters puts the list of writers back into the initial state.
|
||||
|
||||
|
||||
|
||||
## type Config
|
||||
``` go
|
||||
type Config map[string]Level
|
||||
```
|
||||
Config is a mapping of logger module names to logging severity levels.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### func ParseConfigString
|
||||
``` go
|
||||
func ParseConfigString(specification string) (Config, error)
|
||||
```
|
||||
ParseConfigString parses a logger configuration string into a map of logger
|
||||
names and their associated log level. This method is provided to allow
|
||||
other programs to pre-validate a configuration string rather than just
|
||||
calling ConfigureLoggers.
|
||||
|
||||
Logging modules are colon- or semicolon-separated; each module is specified
|
||||
as <modulename>=<level>. White space outside of module names and levels is
|
||||
ignored. The root module is specified with the name "<root>".
|
||||
|
||||
As a special case, a log level may be specified on its own.
|
||||
This is equivalent to specifying the level of the root module,
|
||||
so "DEBUG" is equivalent to `<root>=DEBUG`
|
||||
|
||||
An example specification:
|
||||
|
||||
|
||||
`<root>=ERROR; foo.bar=WARNING`
|
||||
|
||||
|
||||
|
||||
|
||||
### func (Config) String
|
||||
``` go
|
||||
func (c Config) String() string
|
||||
```
|
||||
String returns a logger configuration string that may be parsed
|
||||
using ParseConfigurationString.
|
||||
|
||||
|
||||
|
||||
## type Context
|
||||
``` go
|
||||
type Context struct {
|
||||
// contains filtered or unexported fields
|
||||
}
|
||||
```
|
||||
Context produces loggers for a hierarchy of modules. The context holds
|
||||
a collection of hierarchical loggers and their writers.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### func DefaultContext
|
||||
``` go
|
||||
func DefaultContext() *Context
|
||||
```
|
||||
DefaultContext returns the global default logging context.
|
||||
|
||||
|
||||
### func NewContext
|
||||
``` go
|
||||
func NewContext(rootLevel Level) *Context
|
||||
```
|
||||
NewLoggers returns a new Context with no writers set.
|
||||
If the root level is UNSPECIFIED, WARNING is used.
|
||||
|
||||
|
||||
|
||||
|
||||
### func (\*Context) AddWriter
|
||||
``` go
|
||||
func (c *Context) AddWriter(name string, writer Writer) error
|
||||
```
|
||||
AddWriter adds a writer to the list to be called for each logging call.
|
||||
The name cannot be empty, and the writer cannot be nil. If an existing
|
||||
writer exists with the specified name, an error is returned.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) ApplyConfig
|
||||
``` go
|
||||
func (c *Context) ApplyConfig(config Config)
|
||||
```
|
||||
ApplyConfig configures the logging modules according to the provided config.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) CompleteConfig
|
||||
``` go
|
||||
func (c *Context) CompleteConfig() Config
|
||||
```
|
||||
CompleteConfig returns all the loggers and their defined levels,
|
||||
even if that level is UNSPECIFIED.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) Config
|
||||
``` go
|
||||
func (c *Context) Config() Config
|
||||
```
|
||||
Config returns the current configuration of the Loggers. Loggers
|
||||
with UNSPECIFIED level will not be included.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) GetLogger
|
||||
``` go
|
||||
func (c *Context) GetLogger(name string) Logger
|
||||
```
|
||||
GetLogger returns a Logger for the given module name, creating it and
|
||||
its parents if necessary.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) RemoveWriter
|
||||
``` go
|
||||
func (c *Context) RemoveWriter(name string) (Writer, error)
|
||||
```
|
||||
RemoveWriter remotes the specified writer. If a writer is not found with
|
||||
the specified name an error is returned. The writer that was removed is also
|
||||
returned.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) ReplaceWriter
|
||||
``` go
|
||||
func (c *Context) ReplaceWriter(name string, writer Writer) (Writer, error)
|
||||
```
|
||||
ReplaceWriter is a convenience method that does the equivalent of RemoveWriter
|
||||
followed by AddWriter with the same name. The replaced writer is returned.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) ResetLoggerLevels
|
||||
``` go
|
||||
func (c *Context) ResetLoggerLevels()
|
||||
```
|
||||
ResetLoggerLevels iterates through the known logging modules and sets the
|
||||
levels of all to UNSPECIFIED, except for <root> which is set to WARNING.
|
||||
|
||||
|
||||
|
||||
### func (\*Context) ResetWriters
|
||||
``` go
|
||||
func (c *Context) ResetWriters()
|
||||
```
|
||||
ResetWriters is generally only used in testing and removes all the writers.
|
||||
|
||||
|
||||
|
||||
## type Entry
|
||||
``` go
|
||||
type Entry struct {
|
||||
// Level is the severity of the log message.
|
||||
Level Level
|
||||
// Module is the dotted module name from the logger.
|
||||
Module string
|
||||
// Filename is the full path the file that logged the message.
|
||||
Filename string
|
||||
// Line is the line number of the Filename.
|
||||
Line int
|
||||
// Timestamp is when the log message was created
|
||||
Timestamp time.Time
|
||||
// Message is the formatted string from teh log call.
|
||||
Message string
|
||||
}
|
||||
```
|
||||
Entry represents a single log message.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## type Level
|
||||
``` go
|
||||
type Level uint32
|
||||
```
|
||||
Level holds a severity level.
|
||||
|
||||
|
||||
|
||||
``` go
|
||||
const (
|
||||
UNSPECIFIED Level = iota
|
||||
TRACE
|
||||
DEBUG
|
||||
INFO
|
||||
WARNING
|
||||
ERROR
|
||||
CRITICAL
|
||||
)
|
||||
```
|
||||
The severity levels. Higher values are more considered more
|
||||
important.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### func ParseLevel
|
||||
``` go
|
||||
func ParseLevel(level string) (Level, bool)
|
||||
```
|
||||
ParseLevel converts a string representation of a logging level to a
|
||||
Level. It returns the level and whether it was valid or not.
|
||||
|
||||
|
||||
|
||||
|
||||
### func (Level) Short
|
||||
``` go
|
||||
func (level Level) Short() string
|
||||
```
|
||||
Short returns a five character string to use in
|
||||
aligned logging output.
|
||||
|
||||
|
||||
|
||||
### func (Level) String
|
||||
``` go
|
||||
func (level Level) String() string
|
||||
```
|
||||
String implements Stringer.
|
||||
|
||||
|
||||
|
||||
## type Logger
|
||||
``` go
|
||||
type Logger struct {
|
||||
// contains filtered or unexported fields
|
||||
}
|
||||
```
|
||||
A Logger represents a logging module. It has an associated logging
|
||||
level which can be changed; messages of lesser severity will
|
||||
be dropped. Loggers have a hierarchical relationship - see
|
||||
the package documentation.
|
||||
|
||||
The zero Logger value is usable - any messages logged
|
||||
to it will be sent to the root Logger.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### func GetLogger
|
||||
``` go
|
||||
func GetLogger(name string) Logger
|
||||
```
|
||||
GetLogger returns a Logger for the given module name,
|
||||
creating it and its parents if necessary.
|
||||
|
||||
|
||||
|
||||
|
||||
### func (Logger) Criticalf
|
||||
``` go
|
||||
func (logger Logger) Criticalf(message string, args ...interface{})
|
||||
```
|
||||
Criticalf logs the printf-formatted message at critical level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) Debugf
|
||||
``` go
|
||||
func (logger Logger) Debugf(message string, args ...interface{})
|
||||
```
|
||||
Debugf logs the printf-formatted message at debug level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) EffectiveLogLevel
|
||||
``` go
|
||||
func (logger Logger) EffectiveLogLevel() Level
|
||||
```
|
||||
EffectiveLogLevel returns the effective min log level of
|
||||
the receiver - that is, messages with a lesser severity
|
||||
level will be discarded.
|
||||
|
||||
If the log level of the receiver is unspecified,
|
||||
it will be taken from the effective log level of its
|
||||
parent.
|
||||
|
||||
|
||||
|
||||
### func (Logger) Errorf
|
||||
``` go
|
||||
func (logger Logger) Errorf(message string, args ...interface{})
|
||||
```
|
||||
Errorf logs the printf-formatted message at error level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) Infof
|
||||
``` go
|
||||
func (logger Logger) Infof(message string, args ...interface{})
|
||||
```
|
||||
Infof logs the printf-formatted message at info level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) IsDebugEnabled
|
||||
``` go
|
||||
func (logger Logger) IsDebugEnabled() bool
|
||||
```
|
||||
IsDebugEnabled returns whether debugging is enabled
|
||||
at debug level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) IsErrorEnabled
|
||||
``` go
|
||||
func (logger Logger) IsErrorEnabled() bool
|
||||
```
|
||||
IsErrorEnabled returns whether debugging is enabled
|
||||
at error level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) IsInfoEnabled
|
||||
``` go
|
||||
func (logger Logger) IsInfoEnabled() bool
|
||||
```
|
||||
IsInfoEnabled returns whether debugging is enabled
|
||||
at info level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) IsLevelEnabled
|
||||
``` go
|
||||
func (logger Logger) IsLevelEnabled(level Level) bool
|
||||
```
|
||||
IsLevelEnabled returns whether debugging is enabled
|
||||
for the given log level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) IsTraceEnabled
|
||||
``` go
|
||||
func (logger Logger) IsTraceEnabled() bool
|
||||
```
|
||||
IsTraceEnabled returns whether debugging is enabled
|
||||
at trace level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) IsWarningEnabled
|
||||
``` go
|
||||
func (logger Logger) IsWarningEnabled() bool
|
||||
```
|
||||
IsWarningEnabled returns whether debugging is enabled
|
||||
at warning level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) LogCallf
|
||||
``` go
|
||||
func (logger Logger) LogCallf(calldepth int, level Level, message string, args ...interface{})
|
||||
```
|
||||
LogCallf logs a printf-formatted message at the given level.
|
||||
The location of the call is indicated by the calldepth argument.
|
||||
A calldepth of 1 means the function that called this function.
|
||||
A message will be discarded if level is less than the
|
||||
the effective log level of the logger.
|
||||
Note that the writers may also filter out messages that
|
||||
are less than their registered minimum severity level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) LogLevel
|
||||
``` go
|
||||
func (logger Logger) LogLevel() Level
|
||||
```
|
||||
LogLevel returns the configured min log level of the logger.
|
||||
|
||||
|
||||
|
||||
### func (Logger) Logf
|
||||
``` go
|
||||
func (logger Logger) Logf(level Level, message string, args ...interface{})
|
||||
```
|
||||
Logf logs a printf-formatted message at the given level.
|
||||
A message will be discarded if level is less than the
|
||||
the effective log level of the logger.
|
||||
Note that the writers may also filter out messages that
|
||||
are less than their registered minimum severity level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) Name
|
||||
``` go
|
||||
func (logger Logger) Name() string
|
||||
```
|
||||
Name returns the logger's module name.
|
||||
|
||||
|
||||
|
||||
### func (Logger) SetLogLevel
|
||||
``` go
|
||||
func (logger Logger) SetLogLevel(level Level)
|
||||
```
|
||||
SetLogLevel sets the severity level of the given logger.
|
||||
The root logger cannot be set to UNSPECIFIED level.
|
||||
See EffectiveLogLevel for how this affects the
|
||||
actual messages logged.
|
||||
|
||||
|
||||
|
||||
### func (Logger) Tracef
|
||||
``` go
|
||||
func (logger Logger) Tracef(message string, args ...interface{})
|
||||
```
|
||||
Tracef logs the printf-formatted message at trace level.
|
||||
|
||||
|
||||
|
||||
### func (Logger) Warningf
|
||||
``` go
|
||||
func (logger Logger) Warningf(message string, args ...interface{})
|
||||
```
|
||||
Warningf logs the printf-formatted message at warning level.
|
||||
|
||||
|
||||
|
||||
## type TestWriter
|
||||
``` go
|
||||
type TestWriter struct {
|
||||
// contains filtered or unexported fields
|
||||
}
|
||||
```
|
||||
TestWriter is a useful Writer for testing purposes. Each component of the
|
||||
logging message is stored in the Log array.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### func (\*TestWriter) Clear
|
||||
``` go
|
||||
func (writer *TestWriter) Clear()
|
||||
```
|
||||
Clear removes any saved log messages.
|
||||
|
||||
|
||||
|
||||
### func (\*TestWriter) Log
|
||||
``` go
|
||||
func (writer *TestWriter) Log() []Entry
|
||||
```
|
||||
Log returns a copy of the current logged values.
|
||||
|
||||
|
||||
|
||||
### func (\*TestWriter) Write
|
||||
``` go
|
||||
func (writer *TestWriter) Write(entry Entry)
|
||||
```
|
||||
Write saves the params as members in the TestLogValues struct appended to the Log array.
|
||||
|
||||
|
||||
|
||||
## type Writer
|
||||
``` go
|
||||
type Writer interface {
|
||||
// Write writes a message to the Writer with the given level and module
|
||||
// name. The filename and line hold the file name and line number of the
|
||||
// code that is generating the log message; the time stamp holds the time
|
||||
// the log message was generated, and message holds the log message
|
||||
// itself.
|
||||
Write(entry Entry)
|
||||
}
|
||||
```
|
||||
Writer is implemented by any recipient of log messages.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### func NewColorWriter
|
||||
``` go
|
||||
func NewColorWriter(writer io.Writer) Writer
|
||||
```
|
||||
NewColorWriter will write out colored severity levels if the writer is
|
||||
outputting to a terminal.
|
||||
|
||||
|
||||
### func NewMinimumLevelWriter
|
||||
``` go
|
||||
func NewMinimumLevelWriter(writer Writer, minLevel Level) Writer
|
||||
```
|
||||
NewMinLevelWriter returns a Writer that will only pass on the Write calls
|
||||
to the provided writer if the log level is at or above the specified
|
||||
minimum level.
|
||||
|
||||
|
||||
### func NewSimpleWriter
|
||||
``` go
|
||||
func NewSimpleWriter(writer io.Writer, formatter func(entry Entry) string) Writer
|
||||
```
|
||||
NewSimpleWriter returns a new writer that writes log messages to the given
|
||||
io.Writer formatting the messages with the given formatter.
|
||||
|
||||
|
||||
### func RemoveWriter
|
||||
``` go
|
||||
func RemoveWriter(name string) (Writer, error)
|
||||
```
|
||||
RemoveWriter removes the Writer identified by 'name' and returns it.
|
||||
If the Writer is not found, an error is returned.
|
||||
|
||||
|
||||
### func ReplaceDefaultWriter
|
||||
``` go
|
||||
func ReplaceDefaultWriter(writer Writer) (Writer, error)
|
||||
```
|
||||
ReplaceDefaultWriter is a convenience method that does the equivalent of
|
||||
RemoveWriter and then RegisterWriter with the name "default". The previous
|
||||
default writer, if any is returned.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- - -
|
||||
Generated by [godoc2md](http://godoc.org/github.com/davecheney/godoc2md)
|
105
vendor/github.com/juju/loggo/benchmarks_test.go
generated
vendored
Normal file
105
vendor/github.com/juju/loggo/benchmarks_test.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/juju/loggo"
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type BenchmarksSuite struct {
|
||||
logger loggo.Logger
|
||||
writer *writer
|
||||
}
|
||||
|
||||
var _ = gc.Suite(&BenchmarksSuite{})
|
||||
|
||||
func (s *BenchmarksSuite) SetUpTest(c *gc.C) {
|
||||
loggo.ResetLogging()
|
||||
s.logger = loggo.GetLogger("test.writer")
|
||||
s.writer = &writer{}
|
||||
err := loggo.RegisterWriter("test", s.writer)
|
||||
c.Assert(err, gc.IsNil)
|
||||
}
|
||||
|
||||
func (s *BenchmarksSuite) BenchmarkLoggingNoWriters(c *gc.C) {
|
||||
// No writers
|
||||
loggo.RemoveWriter("test")
|
||||
for i := 0; i < c.N; i++ {
|
||||
s.logger.Warningf("just a simple warning for %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchmarksSuite) BenchmarkLoggingNoWritersNoFormat(c *gc.C) {
|
||||
// No writers
|
||||
loggo.RemoveWriter("test")
|
||||
for i := 0; i < c.N; i++ {
|
||||
s.logger.Warningf("just a simple warning")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BenchmarksSuite) BenchmarkLoggingTestWriters(c *gc.C) {
|
||||
for i := 0; i < c.N; i++ {
|
||||
s.logger.Warningf("just a simple warning for %d", i)
|
||||
}
|
||||
c.Assert(s.writer.Log(), gc.HasLen, c.N)
|
||||
}
|
||||
|
||||
func (s *BenchmarksSuite) BenchmarkLoggingDiskWriter(c *gc.C) {
|
||||
logFile := s.setupTempFileWriter(c)
|
||||
defer logFile.Close()
|
||||
msg := "just a simple warning for %d"
|
||||
for i := 0; i < c.N; i++ {
|
||||
s.logger.Warningf(msg, i)
|
||||
}
|
||||
offset, err := logFile.Seek(0, os.SEEK_CUR)
|
||||
c.Assert(err, gc.IsNil)
|
||||
c.Assert((offset > int64(len(msg))*int64(c.N)), gc.Equals, true,
|
||||
gc.Commentf("Not enough data was written to the log file."))
|
||||
}
|
||||
|
||||
func (s *BenchmarksSuite) BenchmarkLoggingDiskWriterNoMessages(c *gc.C) {
|
||||
logFile := s.setupTempFileWriter(c)
|
||||
defer logFile.Close()
|
||||
// Change the log level
|
||||
writer, err := loggo.RemoveWriter("testfile")
|
||||
c.Assert(err, gc.IsNil)
|
||||
loggo.RegisterWriter("testfile", loggo.NewMinimumLevelWriter(writer, loggo.WARNING))
|
||||
msg := "just a simple warning for %d"
|
||||
for i := 0; i < c.N; i++ {
|
||||
s.logger.Debugf(msg, i)
|
||||
}
|
||||
offset, err := logFile.Seek(0, os.SEEK_CUR)
|
||||
c.Assert(err, gc.IsNil)
|
||||
c.Assert(offset, gc.Equals, int64(0),
|
||||
gc.Commentf("Data was written to the log file."))
|
||||
}
|
||||
|
||||
func (s *BenchmarksSuite) BenchmarkLoggingDiskWriterNoMessagesLogLevel(c *gc.C) {
|
||||
logFile := s.setupTempFileWriter(c)
|
||||
defer logFile.Close()
|
||||
// Change the log level
|
||||
s.logger.SetLogLevel(loggo.WARNING)
|
||||
msg := "just a simple warning for %d"
|
||||
for i := 0; i < c.N; i++ {
|
||||
s.logger.Debugf(msg, i)
|
||||
}
|
||||
offset, err := logFile.Seek(0, os.SEEK_CUR)
|
||||
c.Assert(err, gc.IsNil)
|
||||
c.Assert(offset, gc.Equals, int64(0),
|
||||
gc.Commentf("Data was written to the log file."))
|
||||
}
|
||||
|
||||
func (s *BenchmarksSuite) setupTempFileWriter(c *gc.C) *os.File {
|
||||
loggo.RemoveWriter("test")
|
||||
logFile, err := ioutil.TempFile(c.MkDir(), "loggo-test")
|
||||
c.Assert(err, gc.IsNil)
|
||||
writer := loggo.NewSimpleWriter(logFile, loggo.DefaultFormatter)
|
||||
err = loggo.RegisterWriter("testfile", writer)
|
||||
c.Assert(err, gc.IsNil)
|
||||
return logFile
|
||||
}
|
44
vendor/github.com/juju/loggo/checkers_test.go
generated
vendored
Normal file
44
vendor/github.com/juju/loggo/checkers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func Between(start, end time.Time) gc.Checker {
|
||||
if end.Before(start) {
|
||||
return &betweenChecker{end, start}
|
||||
}
|
||||
return &betweenChecker{start, end}
|
||||
}
|
||||
|
||||
type betweenChecker struct {
|
||||
start, end time.Time
|
||||
}
|
||||
|
||||
func (checker *betweenChecker) Info() *gc.CheckerInfo {
|
||||
info := gc.CheckerInfo{
|
||||
Name: "Between",
|
||||
Params: []string{"obtained"},
|
||||
}
|
||||
return &info
|
||||
}
|
||||
|
||||
func (checker *betweenChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
when, ok := params[0].(time.Time)
|
||||
if !ok {
|
||||
return false, "obtained value type must be time.Time"
|
||||
}
|
||||
if when.Before(checker.start) {
|
||||
return false, fmt.Sprintf("obtained time %q is before start time %q", when, checker.start)
|
||||
}
|
||||
if when.After(checker.end) {
|
||||
return false, fmt.Sprintf("obtained time %q is after end time %q", when, checker.end)
|
||||
}
|
||||
return true, ""
|
||||
}
|
96
vendor/github.com/juju/loggo/config.go
generated
vendored
Normal file
96
vendor/github.com/juju/loggo/config.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Config is a mapping of logger module names to logging severity levels.
|
||||
type Config map[string]Level
|
||||
|
||||
// String returns a logger configuration string that may be parsed
|
||||
// using ParseConfigurationString.
|
||||
func (c Config) String() string {
|
||||
if c == nil {
|
||||
return ""
|
||||
}
|
||||
// output in alphabetical order.
|
||||
names := []string{}
|
||||
for name := range c {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
var entries []string
|
||||
for _, name := range names {
|
||||
level := c[name]
|
||||
if name == "" {
|
||||
name = rootString
|
||||
}
|
||||
entry := fmt.Sprintf("%s=%s", name, level)
|
||||
entries = append(entries, entry)
|
||||
}
|
||||
return strings.Join(entries, ";")
|
||||
}
|
||||
|
||||
func parseConfigValue(value string) (string, Level, error) {
|
||||
pair := strings.SplitN(value, "=", 2)
|
||||
if len(pair) < 2 {
|
||||
return "", UNSPECIFIED, fmt.Errorf("config value expected '=', found %q", value)
|
||||
}
|
||||
name := strings.TrimSpace(pair[0])
|
||||
if name == "" {
|
||||
return "", UNSPECIFIED, fmt.Errorf("config value %q has missing module name", value)
|
||||
}
|
||||
|
||||
levelStr := strings.TrimSpace(pair[1])
|
||||
level, ok := ParseLevel(levelStr)
|
||||
if !ok {
|
||||
return "", UNSPECIFIED, fmt.Errorf("unknown severity level %q", levelStr)
|
||||
}
|
||||
if name == rootString {
|
||||
name = ""
|
||||
}
|
||||
return name, level, nil
|
||||
}
|
||||
|
||||
// ParseConfigString parses a logger configuration string into a map of logger
|
||||
// names and their associated log level. This method is provided to allow
|
||||
// other programs to pre-validate a configuration string rather than just
|
||||
// calling ConfigureLoggers.
|
||||
//
|
||||
// Logging modules are colon- or semicolon-separated; each module is specified
|
||||
// as <modulename>=<level>. White space outside of module names and levels is
|
||||
// ignored. The root module is specified with the name "<root>".
|
||||
//
|
||||
// As a special case, a log level may be specified on its own.
|
||||
// This is equivalent to specifying the level of the root module,
|
||||
// so "DEBUG" is equivalent to `<root>=DEBUG`
|
||||
//
|
||||
// An example specification:
|
||||
// `<root>=ERROR; foo.bar=WARNING`
|
||||
func ParseConfigString(specification string) (Config, error) {
|
||||
specification = strings.TrimSpace(specification)
|
||||
if specification == "" {
|
||||
return nil, nil
|
||||
}
|
||||
cfg := make(Config)
|
||||
if level, ok := ParseLevel(specification); ok {
|
||||
cfg[""] = level
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
values := strings.FieldsFunc(specification, func(r rune) bool { return r == ';' || r == ':' })
|
||||
for _, value := range values {
|
||||
name, level, err := parseConfigValue(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg[name] = level
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
152
vendor/github.com/juju/loggo/config_test.go
generated
vendored
Normal file
152
vendor/github.com/juju/loggo/config_test.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import gc "gopkg.in/check.v1"
|
||||
|
||||
type ConfigSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&ConfigSuite{})
|
||||
|
||||
func (*ConfigSuite) TestParseConfigValue(c *gc.C) {
|
||||
for i, test := range []struct {
|
||||
value string
|
||||
module string
|
||||
level Level
|
||||
err string
|
||||
}{{
|
||||
err: `config value expected '=', found ""`,
|
||||
}, {
|
||||
value: "WARNING",
|
||||
err: `config value expected '=', found "WARNING"`,
|
||||
}, {
|
||||
value: "=WARNING",
|
||||
err: `config value "=WARNING" has missing module name`,
|
||||
}, {
|
||||
value: " name = WARNING ",
|
||||
module: "name",
|
||||
level: WARNING,
|
||||
}, {
|
||||
value: "name = foo",
|
||||
err: `unknown severity level "foo"`,
|
||||
}, {
|
||||
value: "name=DEBUG=INFO",
|
||||
err: `unknown severity level "DEBUG=INFO"`,
|
||||
}, {
|
||||
value: "<root> = info",
|
||||
module: "",
|
||||
level: INFO,
|
||||
}} {
|
||||
c.Logf("%d: %s", i, test.value)
|
||||
module, level, err := parseConfigValue(test.value)
|
||||
if test.err == "" {
|
||||
c.Check(err, gc.IsNil)
|
||||
c.Check(module, gc.Equals, test.module)
|
||||
c.Check(level, gc.Equals, test.level)
|
||||
} else {
|
||||
c.Check(module, gc.Equals, "")
|
||||
c.Check(level, gc.Equals, UNSPECIFIED)
|
||||
c.Check(err.Error(), gc.Equals, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (*ConfigSuite) TestPaarseConfigurationString(c *gc.C) {
|
||||
for i, test := range []struct {
|
||||
configuration string
|
||||
expected Config
|
||||
err string
|
||||
}{{
|
||||
configuration: "",
|
||||
// nil Config, no error
|
||||
}, {
|
||||
configuration: "INFO",
|
||||
expected: Config{"": INFO},
|
||||
}, {
|
||||
configuration: "=INFO",
|
||||
err: `config value "=INFO" has missing module name`,
|
||||
}, {
|
||||
configuration: "<root>=UNSPECIFIED",
|
||||
expected: Config{"": UNSPECIFIED},
|
||||
}, {
|
||||
configuration: "<root>=DEBUG",
|
||||
expected: Config{"": DEBUG},
|
||||
}, {
|
||||
configuration: "test.module=debug",
|
||||
expected: Config{"test.module": DEBUG},
|
||||
}, {
|
||||
configuration: "module=info; sub.module=debug; other.module=warning",
|
||||
expected: Config{
|
||||
"module": INFO,
|
||||
"sub.module": DEBUG,
|
||||
"other.module": WARNING,
|
||||
},
|
||||
}, {
|
||||
// colons not semicolons
|
||||
configuration: "module=info: sub.module=debug: other.module=warning",
|
||||
expected: Config{
|
||||
"module": INFO,
|
||||
"sub.module": DEBUG,
|
||||
"other.module": WARNING,
|
||||
},
|
||||
}, {
|
||||
configuration: " foo.bar \t\r\n= \t\r\nCRITICAL \t\r\n; \t\r\nfoo \r\t\n = DEBUG",
|
||||
expected: Config{
|
||||
"foo": DEBUG,
|
||||
"foo.bar": CRITICAL,
|
||||
},
|
||||
}, {
|
||||
configuration: "foo;bar",
|
||||
err: `config value expected '=', found "foo"`,
|
||||
}, {
|
||||
configuration: "foo=",
|
||||
err: `unknown severity level ""`,
|
||||
}, {
|
||||
configuration: "foo=unknown",
|
||||
err: `unknown severity level "unknown"`,
|
||||
}} {
|
||||
c.Logf("%d: %q", i, test.configuration)
|
||||
config, err := ParseConfigString(test.configuration)
|
||||
if test.err == "" {
|
||||
c.Check(err, gc.IsNil)
|
||||
c.Check(config, gc.DeepEquals, test.expected)
|
||||
} else {
|
||||
c.Check(config, gc.IsNil)
|
||||
c.Check(err.Error(), gc.Equals, test.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (*ConfigSuite) TestConfigString(c *gc.C) {
|
||||
for i, test := range []struct {
|
||||
config Config
|
||||
expected string
|
||||
}{{
|
||||
config: nil,
|
||||
expected: "",
|
||||
}, {
|
||||
config: Config{"": INFO},
|
||||
expected: "<root>=INFO",
|
||||
}, {
|
||||
config: Config{"": UNSPECIFIED},
|
||||
expected: "<root>=UNSPECIFIED",
|
||||
}, {
|
||||
config: Config{"": DEBUG},
|
||||
expected: "<root>=DEBUG",
|
||||
}, {
|
||||
config: Config{"test.module": DEBUG},
|
||||
expected: "test.module=DEBUG",
|
||||
}, {
|
||||
config: Config{
|
||||
"": WARNING,
|
||||
"module": INFO,
|
||||
"sub.module": DEBUG,
|
||||
"other.module": WARNING,
|
||||
},
|
||||
expected: "<root>=WARNING;module=INFO;other.module=WARNING;sub.module=DEBUG",
|
||||
}} {
|
||||
c.Logf("%d: %q", i, test.expected)
|
||||
c.Check(test.config.String(), gc.Equals, test.expected)
|
||||
}
|
||||
}
|
198
vendor/github.com/juju/loggo/context.go
generated
vendored
Normal file
198
vendor/github.com/juju/loggo/context.go
generated
vendored
Normal file
|
@ -0,0 +1,198 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Context produces loggers for a hierarchy of modules. The context holds
|
||||
// a collection of hierarchical loggers and their writers.
|
||||
type Context struct {
|
||||
root *module
|
||||
|
||||
// Perhaps have one mutex?
|
||||
modulesMutex sync.Mutex
|
||||
modules map[string]*module
|
||||
|
||||
writersMutex sync.Mutex
|
||||
writers map[string]Writer
|
||||
|
||||
// writeMuxtex is used to serialise write operations.
|
||||
writeMutex sync.Mutex
|
||||
}
|
||||
|
||||
// NewLoggers returns a new Context with no writers set.
|
||||
// If the root level is UNSPECIFIED, WARNING is used.
|
||||
func NewContext(rootLevel Level) *Context {
|
||||
if rootLevel < TRACE || rootLevel > CRITICAL {
|
||||
rootLevel = WARNING
|
||||
}
|
||||
context := &Context{
|
||||
modules: make(map[string]*module),
|
||||
writers: make(map[string]Writer),
|
||||
}
|
||||
context.root = &module{
|
||||
level: rootLevel,
|
||||
context: context,
|
||||
}
|
||||
context.modules[""] = context.root
|
||||
return context
|
||||
}
|
||||
|
||||
// GetLogger returns a Logger for the given module name, creating it and
|
||||
// its parents if necessary.
|
||||
func (c *Context) GetLogger(name string) Logger {
|
||||
name = strings.TrimSpace(strings.ToLower(name))
|
||||
c.modulesMutex.Lock()
|
||||
defer c.modulesMutex.Unlock()
|
||||
return Logger{c.getLoggerModule(name)}
|
||||
}
|
||||
|
||||
func (c *Context) getLoggerModule(name string) *module {
|
||||
if name == rootString {
|
||||
name = ""
|
||||
}
|
||||
impl, found := c.modules[name]
|
||||
if found {
|
||||
return impl
|
||||
}
|
||||
parentName := ""
|
||||
if i := strings.LastIndex(name, "."); i >= 0 {
|
||||
parentName = name[0:i]
|
||||
}
|
||||
parent := c.getLoggerModule(parentName)
|
||||
impl = &module{name, UNSPECIFIED, parent, c}
|
||||
c.modules[name] = impl
|
||||
return impl
|
||||
}
|
||||
|
||||
// Config returns the current configuration of the Loggers. Loggers
|
||||
// with UNSPECIFIED level will not be included.
|
||||
func (c *Context) Config() Config {
|
||||
result := make(Config)
|
||||
c.modulesMutex.Lock()
|
||||
defer c.modulesMutex.Unlock()
|
||||
|
||||
for name, module := range c.modules {
|
||||
if module.level != UNSPECIFIED {
|
||||
result[name] = module.level
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CompleteConfig returns all the loggers and their defined levels,
|
||||
// even if that level is UNSPECIFIED.
|
||||
func (c *Context) CompleteConfig() Config {
|
||||
result := make(Config)
|
||||
c.modulesMutex.Lock()
|
||||
defer c.modulesMutex.Unlock()
|
||||
|
||||
for name, module := range c.modules {
|
||||
result[name] = module.level
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// ApplyConfig configures the logging modules according to the provided config.
|
||||
func (c *Context) ApplyConfig(config Config) {
|
||||
c.modulesMutex.Lock()
|
||||
defer c.modulesMutex.Unlock()
|
||||
for name, level := range config {
|
||||
module := c.getLoggerModule(name)
|
||||
module.setLevel(level)
|
||||
}
|
||||
}
|
||||
|
||||
// ResetLoggerLevels iterates through the known logging modules and sets the
|
||||
// levels of all to UNSPECIFIED, except for <root> which is set to WARNING.
|
||||
func (c *Context) ResetLoggerLevels() {
|
||||
c.modulesMutex.Lock()
|
||||
defer c.modulesMutex.Unlock()
|
||||
// Setting the root module to UNSPECIFIED will set it to WARNING.
|
||||
for _, module := range c.modules {
|
||||
module.setLevel(UNSPECIFIED)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) write(entry Entry) {
|
||||
c.writeMutex.Lock()
|
||||
defer c.writeMutex.Unlock()
|
||||
for _, writer := range c.getWriters() {
|
||||
writer.Write(entry)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) getWriters() []Writer {
|
||||
c.writersMutex.Lock()
|
||||
defer c.writersMutex.Unlock()
|
||||
var result []Writer
|
||||
for _, writer := range c.writers {
|
||||
result = append(result, writer)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// AddWriter adds a writer to the list to be called for each logging call.
|
||||
// The name cannot be empty, and the writer cannot be nil. If an existing
|
||||
// writer exists with the specified name, an error is returned.
|
||||
func (c *Context) AddWriter(name string, writer Writer) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("name cannot be empty")
|
||||
}
|
||||
if writer == nil {
|
||||
return fmt.Errorf("writer cannot be nil")
|
||||
}
|
||||
c.writersMutex.Lock()
|
||||
defer c.writersMutex.Unlock()
|
||||
if _, found := c.writers[name]; found {
|
||||
return fmt.Errorf("context already has a writer named %q", name)
|
||||
}
|
||||
c.writers[name] = writer
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveWriter remotes the specified writer. If a writer is not found with
|
||||
// the specified name an error is returned. The writer that was removed is also
|
||||
// returned.
|
||||
func (c *Context) RemoveWriter(name string) (Writer, error) {
|
||||
c.writersMutex.Lock()
|
||||
defer c.writersMutex.Unlock()
|
||||
reg, found := c.writers[name]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("context has no writer named %q", name)
|
||||
}
|
||||
delete(c.writers, name)
|
||||
return reg, nil
|
||||
}
|
||||
|
||||
// ReplaceWriter is a convenience method that does the equivalent of RemoveWriter
|
||||
// followed by AddWriter with the same name. The replaced writer is returned.
|
||||
func (c *Context) ReplaceWriter(name string, writer Writer) (Writer, error) {
|
||||
if name == "" {
|
||||
return nil, fmt.Errorf("name cannot be empty")
|
||||
}
|
||||
if writer == nil {
|
||||
return nil, fmt.Errorf("writer cannot be nil")
|
||||
}
|
||||
c.writersMutex.Lock()
|
||||
defer c.writersMutex.Unlock()
|
||||
reg, found := c.writers[name]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("context has no writer named %q", name)
|
||||
}
|
||||
oldWriter := reg
|
||||
c.writers[name] = writer
|
||||
return oldWriter, nil
|
||||
}
|
||||
|
||||
// ResetWriters is generally only used in testing and removes all the writers.
|
||||
func (c *Context) ResetWriters() {
|
||||
c.writersMutex.Lock()
|
||||
defer c.writersMutex.Unlock()
|
||||
c.writers = make(map[string]Writer)
|
||||
}
|
328
vendor/github.com/juju/loggo/context_test.go
generated
vendored
Normal file
328
vendor/github.com/juju/loggo/context_test.go
generated
vendored
Normal file
|
@ -0,0 +1,328 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"github.com/juju/loggo"
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type ContextSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&ContextSuite{})
|
||||
|
||||
func (*ContextSuite) TestNewContextRootLevel(c *gc.C) {
|
||||
for i, test := range []struct {
|
||||
level loggo.Level
|
||||
expected loggo.Level
|
||||
}{{
|
||||
level: loggo.UNSPECIFIED,
|
||||
expected: loggo.WARNING,
|
||||
}, {
|
||||
level: loggo.DEBUG,
|
||||
expected: loggo.DEBUG,
|
||||
}, {
|
||||
level: loggo.INFO,
|
||||
expected: loggo.INFO,
|
||||
}, {
|
||||
level: loggo.WARNING,
|
||||
expected: loggo.WARNING,
|
||||
}, {
|
||||
level: loggo.ERROR,
|
||||
expected: loggo.ERROR,
|
||||
}, {
|
||||
level: loggo.CRITICAL,
|
||||
expected: loggo.CRITICAL,
|
||||
}, {
|
||||
level: loggo.Level(42),
|
||||
expected: loggo.WARNING,
|
||||
}} {
|
||||
c.Log("%d: %s", i, test.level)
|
||||
context := loggo.NewContext(test.level)
|
||||
cfg := context.Config()
|
||||
c.Check(cfg, gc.HasLen, 1)
|
||||
value, found := cfg[""]
|
||||
c.Check(found, gc.Equals, true)
|
||||
c.Check(value, gc.Equals, test.expected)
|
||||
}
|
||||
}
|
||||
|
||||
func logAllSeverities(logger loggo.Logger) {
|
||||
logger.Criticalf("something critical")
|
||||
logger.Errorf("an error")
|
||||
logger.Warningf("a warning message")
|
||||
logger.Infof("an info message")
|
||||
logger.Debugf("a debug message")
|
||||
logger.Tracef("a trace message")
|
||||
}
|
||||
|
||||
func checkLogEntry(c *gc.C, entry, expected loggo.Entry) {
|
||||
c.Check(entry.Level, gc.Equals, expected.Level)
|
||||
c.Check(entry.Module, gc.Equals, expected.Module)
|
||||
c.Check(entry.Message, gc.Equals, expected.Message)
|
||||
}
|
||||
|
||||
func checkLogEntries(c *gc.C, obtained, expected []loggo.Entry) {
|
||||
if c.Check(len(obtained), gc.Equals, len(expected)) {
|
||||
for i := range obtained {
|
||||
checkLogEntry(c, obtained[i], expected[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestGetLoggerRoot(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
blank := context.GetLogger("")
|
||||
root := context.GetLogger("<root>")
|
||||
c.Assert(blank, gc.Equals, root)
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestGetLoggerCase(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
upper := context.GetLogger("TEST")
|
||||
lower := context.GetLogger("test")
|
||||
c.Assert(upper, gc.Equals, lower)
|
||||
c.Assert(upper.Name(), gc.Equals, "test")
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestGetLoggerSpace(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
space := context.GetLogger(" test ")
|
||||
lower := context.GetLogger("test")
|
||||
c.Assert(space, gc.Equals, lower)
|
||||
c.Assert(space.Name(), gc.Equals, "test")
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestNewContextNoWriter(c *gc.C) {
|
||||
// Should be no output.
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
logger := context.GetLogger("test")
|
||||
logAllSeverities(logger)
|
||||
}
|
||||
|
||||
func (*ContextSuite) newContextWithTestWriter(c *gc.C, level loggo.Level) (*loggo.Context, *loggo.TestWriter) {
|
||||
writer := &loggo.TestWriter{}
|
||||
context := loggo.NewContext(level)
|
||||
context.AddWriter("test", writer)
|
||||
return context, writer
|
||||
}
|
||||
|
||||
func (s *ContextSuite) TestNewContextRootSeverityWarning(c *gc.C) {
|
||||
context, writer := s.newContextWithTestWriter(c, loggo.WARNING)
|
||||
logger := context.GetLogger("test")
|
||||
logAllSeverities(logger)
|
||||
checkLogEntries(c, writer.Log(), []loggo.Entry{
|
||||
{Level: loggo.CRITICAL, Module: "test", Message: "something critical"},
|
||||
{Level: loggo.ERROR, Module: "test", Message: "an error"},
|
||||
{Level: loggo.WARNING, Module: "test", Message: "a warning message"},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ContextSuite) TestNewContextRootSeverityTrace(c *gc.C) {
|
||||
context, writer := s.newContextWithTestWriter(c, loggo.TRACE)
|
||||
logger := context.GetLogger("test")
|
||||
logAllSeverities(logger)
|
||||
checkLogEntries(c, writer.Log(), []loggo.Entry{
|
||||
{Level: loggo.CRITICAL, Module: "test", Message: "something critical"},
|
||||
{Level: loggo.ERROR, Module: "test", Message: "an error"},
|
||||
{Level: loggo.WARNING, Module: "test", Message: "a warning message"},
|
||||
{Level: loggo.INFO, Module: "test", Message: "an info message"},
|
||||
{Level: loggo.DEBUG, Module: "test", Message: "a debug message"},
|
||||
{Level: loggo.TRACE, Module: "test", Message: "a trace message"},
|
||||
})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestNewContextConfig(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
config := context.Config()
|
||||
c.Assert(config, gc.DeepEquals, loggo.Config{"": loggo.DEBUG})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestNewLoggerAddsConfig(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
_ = context.GetLogger("test.module")
|
||||
c.Assert(context.Config(), gc.DeepEquals, loggo.Config{
|
||||
"": loggo.DEBUG,
|
||||
})
|
||||
c.Assert(context.CompleteConfig(), gc.DeepEquals, loggo.Config{
|
||||
"": loggo.DEBUG,
|
||||
"test": loggo.UNSPECIFIED,
|
||||
"test.module": loggo.UNSPECIFIED,
|
||||
})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestApplyNilConfig(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
context.ApplyConfig(nil)
|
||||
c.Assert(context.Config(), gc.DeepEquals, loggo.Config{"": loggo.DEBUG})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestApplyConfigRootUnspecified(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
context.ApplyConfig(loggo.Config{"": loggo.UNSPECIFIED})
|
||||
c.Assert(context.Config(), gc.DeepEquals, loggo.Config{"": loggo.WARNING})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestApplyConfigRootTrace(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.WARNING)
|
||||
context.ApplyConfig(loggo.Config{"": loggo.TRACE})
|
||||
c.Assert(context.Config(), gc.DeepEquals, loggo.Config{"": loggo.TRACE})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestApplyConfigCreatesModules(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.WARNING)
|
||||
context.ApplyConfig(loggo.Config{"first.second": loggo.TRACE})
|
||||
c.Assert(context.Config(), gc.DeepEquals,
|
||||
loggo.Config{
|
||||
"": loggo.WARNING,
|
||||
"first.second": loggo.TRACE,
|
||||
})
|
||||
c.Assert(context.CompleteConfig(), gc.DeepEquals,
|
||||
loggo.Config{
|
||||
"": loggo.WARNING,
|
||||
"first": loggo.UNSPECIFIED,
|
||||
"first.second": loggo.TRACE,
|
||||
})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestApplyConfigAdditive(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.WARNING)
|
||||
context.ApplyConfig(loggo.Config{"first.second": loggo.TRACE})
|
||||
context.ApplyConfig(loggo.Config{"other.module": loggo.DEBUG})
|
||||
c.Assert(context.Config(), gc.DeepEquals,
|
||||
loggo.Config{
|
||||
"": loggo.WARNING,
|
||||
"first.second": loggo.TRACE,
|
||||
"other.module": loggo.DEBUG,
|
||||
})
|
||||
c.Assert(context.CompleteConfig(), gc.DeepEquals,
|
||||
loggo.Config{
|
||||
"": loggo.WARNING,
|
||||
"first": loggo.UNSPECIFIED,
|
||||
"first.second": loggo.TRACE,
|
||||
"other": loggo.UNSPECIFIED,
|
||||
"other.module": loggo.DEBUG,
|
||||
})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestResetLoggerLevels(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
context.ApplyConfig(loggo.Config{"first.second": loggo.TRACE})
|
||||
context.ResetLoggerLevels()
|
||||
c.Assert(context.Config(), gc.DeepEquals,
|
||||
loggo.Config{
|
||||
"": loggo.WARNING,
|
||||
})
|
||||
c.Assert(context.CompleteConfig(), gc.DeepEquals,
|
||||
loggo.Config{
|
||||
"": loggo.WARNING,
|
||||
"first": loggo.UNSPECIFIED,
|
||||
"first.second": loggo.UNSPECIFIED,
|
||||
})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestWriterNamesNone(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
writers := context.WriterNames()
|
||||
c.Assert(writers, gc.HasLen, 0)
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestAddWriterNoName(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
err := context.AddWriter("", nil)
|
||||
c.Assert(err.Error(), gc.Equals, "name cannot be empty")
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestAddWriterNil(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
err := context.AddWriter("foo", nil)
|
||||
c.Assert(err.Error(), gc.Equals, "writer cannot be nil")
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestNamedAddWriter(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
err := context.AddWriter("foo", &writer{name: "foo"})
|
||||
c.Assert(err, gc.IsNil)
|
||||
err = context.AddWriter("foo", &writer{name: "foo"})
|
||||
c.Assert(err.Error(), gc.Equals, `context already has a writer named "foo"`)
|
||||
|
||||
writers := context.WriterNames()
|
||||
c.Assert(writers, gc.DeepEquals, []string{"foo"})
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestRemoveWriter(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
w, err := context.RemoveWriter("unknown")
|
||||
c.Assert(err.Error(), gc.Equals, `context has no writer named "unknown"`)
|
||||
c.Assert(w, gc.IsNil)
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestRemoveWriterFound(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
original := &writer{name: "foo"}
|
||||
err := context.AddWriter("foo", original)
|
||||
c.Assert(err, gc.IsNil)
|
||||
existing, err := context.RemoveWriter("foo")
|
||||
c.Assert(err, gc.IsNil)
|
||||
c.Assert(existing, gc.Equals, original)
|
||||
|
||||
writers := context.WriterNames()
|
||||
c.Assert(writers, gc.HasLen, 0)
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestReplaceWriterNoName(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
existing, err := context.ReplaceWriter("", nil)
|
||||
c.Assert(err.Error(), gc.Equals, "name cannot be empty")
|
||||
c.Assert(existing, gc.IsNil)
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestReplaceWriterNil(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
existing, err := context.ReplaceWriter("foo", nil)
|
||||
c.Assert(err.Error(), gc.Equals, "writer cannot be nil")
|
||||
c.Assert(existing, gc.IsNil)
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestReplaceWriterNotFound(c *gc.C) {
|
||||
context := loggo.NewContext(loggo.DEBUG)
|
||||
existing, err := context.ReplaceWriter("foo", &writer{})
|
||||
c.Assert(err.Error(), gc.Equals, `context has no writer named "foo"`)
|
||||
c.Assert(existing, gc.IsNil)
|
||||
}
|
||||
|
||||
func (*ContextSuite) TestMultipleWriters(c *gc.C) {
|
||||
first := &writer{}
|
||||
second := &writer{}
|
||||
third := &writer{}
|
||||
context := loggo.NewContext(loggo.TRACE)
|
||||
err := context.AddWriter("first", first)
|
||||
c.Assert(err, gc.IsNil)
|
||||
err = context.AddWriter("second", second)
|
||||
c.Assert(err, gc.IsNil)
|
||||
err = context.AddWriter("third", third)
|
||||
c.Assert(err, gc.IsNil)
|
||||
|
||||
logger := context.GetLogger("test")
|
||||
logAllSeverities(logger)
|
||||
|
||||
expected := []loggo.Entry{
|
||||
{Level: loggo.CRITICAL, Module: "test", Message: "something critical"},
|
||||
{Level: loggo.ERROR, Module: "test", Message: "an error"},
|
||||
{Level: loggo.WARNING, Module: "test", Message: "a warning message"},
|
||||
{Level: loggo.INFO, Module: "test", Message: "an info message"},
|
||||
{Level: loggo.DEBUG, Module: "test", Message: "a debug message"},
|
||||
{Level: loggo.TRACE, Module: "test", Message: "a trace message"},
|
||||
}
|
||||
|
||||
checkLogEntries(c, first.Log(), expected)
|
||||
checkLogEntries(c, second.Log(), expected)
|
||||
checkLogEntries(c, third.Log(), expected)
|
||||
}
|
||||
|
||||
type writer struct {
|
||||
loggo.TestWriter
|
||||
// The name exists to discriminate writer equality.
|
||||
name string
|
||||
}
|
6
vendor/github.com/juju/loggo/dependencies.tsv
generated
vendored
Normal file
6
vendor/github.com/juju/loggo/dependencies.tsv
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
github.com/juju/ansiterm git b99631de12cf04a906c1d4e4ec54fb86eae5863d 2016-09-07T23:45:32Z
|
||||
github.com/lunixbochs/vtclean git 4fbf7632a2c6d3fbdb9931439bdbbeded02cbe36 2016-01-25T03:51:06Z
|
||||
github.com/mattn/go-colorable git ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8 2016-07-31T23:54:17Z
|
||||
github.com/mattn/go-isatty git 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8 2016-08-06T12:27:52Z
|
||||
golang.org/x/sys git 9bb9f0998d48b31547d975974935ae9b48c7a03c 2016-10-12T00:19:20Z
|
||||
gopkg.in/check.v1 git 4f90aeace3a26ad7021961c297b22c42160c7b25 2016-01-05T16:49:36Z
|
|
47
vendor/github.com/juju/loggo/doc.go
generated
vendored
Normal file
47
vendor/github.com/juju/loggo/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
/*
|
||||
[godoc-link-here]
|
||||
|
||||
Module level logging for Go
|
||||
|
||||
This package provides an alternative to the standard library log package.
|
||||
|
||||
The actual logging functions never return errors. If you are logging
|
||||
something, you really don't want to be worried about the logging
|
||||
having trouble.
|
||||
|
||||
Modules have names that are defined by dotted strings.
|
||||
"first.second.third"
|
||||
|
||||
There is a root module that has the name `""`. Each module
|
||||
(except the root module) has a parent, identified by the part of
|
||||
the name without the last dotted value.
|
||||
* the parent of "first.second.third" is "first.second"
|
||||
* the parent of "first.second" is "first"
|
||||
* the parent of "first" is "" (the root module)
|
||||
|
||||
Each module can specify its own severity level. Logging calls that are of
|
||||
a lower severity than the module's effective severity level are not written
|
||||
out.
|
||||
|
||||
Loggers are created using the GetLogger function.
|
||||
logger := loggo.GetLogger("foo.bar")
|
||||
|
||||
By default there is one writer registered, which will write to Stderr,
|
||||
and the root module, which will only emit warnings and above.
|
||||
If you want to continue using the default
|
||||
logger, but have it emit all logging levels you need to do the following.
|
||||
|
||||
writer, _, err := loggo.RemoveWriter("default")
|
||||
// err is non-nil if and only if the name isn't found.
|
||||
loggo.RegisterWriter("default", writer)
|
||||
|
||||
To make loggo produce colored output, you can do the following,
|
||||
having imported github.com/juju/loggo/loggocolor:
|
||||
|
||||
loggo.RemoveWriter("default")
|
||||
loggo.RegisterWriter("default", loggocolor.NewWriter(os.Stderr))
|
||||
*/
|
||||
package loggo
|
22
vendor/github.com/juju/loggo/entry.go
generated
vendored
Normal file
22
vendor/github.com/juju/loggo/entry.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import "time"
|
||||
|
||||
// Entry represents a single log message.
|
||||
type Entry struct {
|
||||
// Level is the severity of the log message.
|
||||
Level Level
|
||||
// Module is the dotted module name from the logger.
|
||||
Module string
|
||||
// Filename is the full path the file that logged the message.
|
||||
Filename string
|
||||
// Line is the line number of the Filename.
|
||||
Line int
|
||||
// Timestamp is when the log message was created
|
||||
Timestamp time.Time
|
||||
// Message is the formatted string from teh log call.
|
||||
Message string
|
||||
}
|
20
vendor/github.com/juju/loggo/export_test.go
generated
vendored
Normal file
20
vendor/github.com/juju/loggo/export_test.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
// WriterNames returns the names of the context's writers for testing purposes.
|
||||
func (c *Context) WriterNames() []string {
|
||||
c.writersMutex.Lock()
|
||||
defer c.writersMutex.Unlock()
|
||||
var result []string
|
||||
for name := range c.writers {
|
||||
result = append(result, name)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ResetDefaultContext() {
|
||||
ResetLogging()
|
||||
DefaultContext().AddWriter(DefaultWriterName, defaultWriter())
|
||||
}
|
38
vendor/github.com/juju/loggo/formatter.go
generated
vendored
Normal file
38
vendor/github.com/juju/loggo/formatter.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DefaultFormatter returns the parameters separated by spaces except for
|
||||
// filename and line which are separated by a colon. The timestamp is shown
|
||||
// to second resolution in UTC. For example:
|
||||
// 2016-07-02 15:04:05
|
||||
func DefaultFormatter(entry Entry) string {
|
||||
ts := entry.Timestamp.In(time.UTC).Format("2006-01-02 15:04:05")
|
||||
// Just get the basename from the filename
|
||||
filename := filepath.Base(entry.Filename)
|
||||
return fmt.Sprintf("%s %s %s %s:%d %s", ts, entry.Level, entry.Module, filename, entry.Line, entry.Message)
|
||||
}
|
||||
|
||||
// TimeFormat is the time format used for the default writer.
|
||||
// This can be set with the environment variable LOGGO_TIME_FORMAT.
|
||||
var TimeFormat = initTimeFormat()
|
||||
|
||||
func initTimeFormat() string {
|
||||
format := os.Getenv("LOGGO_TIME_FORMAT")
|
||||
if format != "" {
|
||||
return format
|
||||
}
|
||||
return "15:04:05"
|
||||
}
|
||||
|
||||
func formatTime(ts time.Time) string {
|
||||
return ts.Format(TimeFormat)
|
||||
}
|
32
vendor/github.com/juju/loggo/formatter_test.go
generated
vendored
Normal file
32
vendor/github.com/juju/loggo/formatter_test.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/loggo"
|
||||
)
|
||||
|
||||
type formatterSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&formatterSuite{})
|
||||
|
||||
func (*formatterSuite) TestDefaultFormat(c *gc.C) {
|
||||
location, err := time.LoadLocation("UTC")
|
||||
testTime := time.Date(2013, 5, 3, 10, 53, 24, 123456, location)
|
||||
c.Assert(err, gc.IsNil)
|
||||
entry := loggo.Entry{
|
||||
Level: loggo.WARNING,
|
||||
Module: "test.module",
|
||||
Filename: "some/deep/filename",
|
||||
Line: 42,
|
||||
Timestamp: testTime,
|
||||
Message: "hello world!",
|
||||
}
|
||||
formatted := loggo.DefaultFormatter(entry)
|
||||
c.Assert(formatted, gc.Equals, "2013-05-03 10:53:24 WARNING test.module filename:42 hello world!")
|
||||
}
|
85
vendor/github.com/juju/loggo/global.go
generated
vendored
Normal file
85
vendor/github.com/juju/loggo/global.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
var (
|
||||
defaultContext = newDefaultContxt()
|
||||
)
|
||||
|
||||
func newDefaultContxt() *Context {
|
||||
ctx := NewContext(WARNING)
|
||||
ctx.AddWriter(DefaultWriterName, defaultWriter())
|
||||
return ctx
|
||||
}
|
||||
|
||||
// DefaultContext returns the global default logging context.
|
||||
func DefaultContext() *Context {
|
||||
return defaultContext
|
||||
}
|
||||
|
||||
// LoggerInfo returns information about the configured loggers and their
|
||||
// logging levels. The information is returned in the format expected by
|
||||
// ConfigureLoggers. Loggers with UNSPECIFIED level will not
|
||||
// be included.
|
||||
func LoggerInfo() string {
|
||||
return defaultContext.Config().String()
|
||||
}
|
||||
|
||||
// GetLogger returns a Logger for the given module name,
|
||||
// creating it and its parents if necessary.
|
||||
func GetLogger(name string) Logger {
|
||||
return defaultContext.GetLogger(name)
|
||||
}
|
||||
|
||||
// ResetLogging iterates through the known modules and sets the levels of all
|
||||
// to UNSPECIFIED, except for <root> which is set to WARNING. The call also
|
||||
// removes all writers in the DefaultContext and puts the original default
|
||||
// writer back as the only writer.
|
||||
func ResetLogging() {
|
||||
defaultContext.ResetLoggerLevels()
|
||||
defaultContext.ResetWriters()
|
||||
}
|
||||
|
||||
// ResetWriters puts the list of writers back into the initial state.
|
||||
func ResetWriters() {
|
||||
defaultContext.ResetWriters()
|
||||
}
|
||||
|
||||
// ReplaceDefaultWriter is a convenience method that does the equivalent of
|
||||
// RemoveWriter and then RegisterWriter with the name "default". The previous
|
||||
// default writer, if any is returned.
|
||||
func ReplaceDefaultWriter(writer Writer) (Writer, error) {
|
||||
return defaultContext.ReplaceWriter(DefaultWriterName, writer)
|
||||
}
|
||||
|
||||
// RegisterWriter adds the writer to the list of writers in the DefaultContext
|
||||
// that get notified when logging. If there is already a registered writer
|
||||
// with that name, an error is returned.
|
||||
func RegisterWriter(name string, writer Writer) error {
|
||||
return defaultContext.AddWriter(name, writer)
|
||||
}
|
||||
|
||||
// RemoveWriter removes the Writer identified by 'name' and returns it.
|
||||
// If the Writer is not found, an error is returned.
|
||||
func RemoveWriter(name string) (Writer, error) {
|
||||
return defaultContext.RemoveWriter(name)
|
||||
}
|
||||
|
||||
// ConfigureLoggers configures loggers according to the given string
|
||||
// specification, which specifies a set of modules and their associated
|
||||
// logging levels. Loggers are colon- or semicolon-separated; each
|
||||
// module is specified as <modulename>=<level>. White space outside of
|
||||
// module names and levels is ignored. The root module is specified
|
||||
// with the name "<root>".
|
||||
//
|
||||
// An example specification:
|
||||
// `<root>=ERROR; foo.bar=WARNING`
|
||||
func ConfigureLoggers(specification string) error {
|
||||
config, err := ParseConfigString(specification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defaultContext.ApplyConfig(config)
|
||||
return nil
|
||||
}
|
87
vendor/github.com/juju/loggo/global_test.go
generated
vendored
Normal file
87
vendor/github.com/juju/loggo/global_test.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"github.com/juju/loggo"
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type GlobalSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&GlobalSuite{})
|
||||
|
||||
func (*GlobalSuite) SetUpTest(c *gc.C) {
|
||||
loggo.ResetDefaultContext()
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestRootLogger(c *gc.C) {
|
||||
var root loggo.Logger
|
||||
|
||||
got := loggo.GetLogger("")
|
||||
|
||||
c.Check(got.Name(), gc.Equals, root.Name())
|
||||
c.Check(got.LogLevel(), gc.Equals, root.LogLevel())
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestModuleName(c *gc.C) {
|
||||
logger := loggo.GetLogger("loggo.testing")
|
||||
c.Check(logger.Name(), gc.Equals, "loggo.testing")
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestLevel(c *gc.C) {
|
||||
logger := loggo.GetLogger("testing")
|
||||
level := logger.LogLevel()
|
||||
c.Check(level, gc.Equals, loggo.UNSPECIFIED)
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestEffectiveLevel(c *gc.C) {
|
||||
logger := loggo.GetLogger("testing")
|
||||
level := logger.EffectiveLogLevel()
|
||||
c.Check(level, gc.Equals, loggo.WARNING)
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestLevelsSharedForSameModule(c *gc.C) {
|
||||
logger1 := loggo.GetLogger("testing.module")
|
||||
logger2 := loggo.GetLogger("testing.module")
|
||||
|
||||
logger1.SetLogLevel(loggo.INFO)
|
||||
c.Assert(logger1.IsInfoEnabled(), gc.Equals, true)
|
||||
c.Assert(logger2.IsInfoEnabled(), gc.Equals, true)
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestModuleLowered(c *gc.C) {
|
||||
logger1 := loggo.GetLogger("TESTING.MODULE")
|
||||
logger2 := loggo.GetLogger("Testing")
|
||||
|
||||
c.Assert(logger1.Name(), gc.Equals, "testing.module")
|
||||
c.Assert(logger2.Name(), gc.Equals, "testing")
|
||||
}
|
||||
|
||||
func (s *GlobalSuite) TestConfigureLoggers(c *gc.C) {
|
||||
err := loggo.ConfigureLoggers("testing.module=debug")
|
||||
c.Assert(err, gc.IsNil)
|
||||
expected := "<root>=WARNING;testing.module=DEBUG"
|
||||
c.Assert(loggo.DefaultContext().Config().String(), gc.Equals, expected)
|
||||
c.Assert(loggo.LoggerInfo(), gc.Equals, expected)
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestRegisterWriterExistingName(c *gc.C) {
|
||||
err := loggo.RegisterWriter("default", &writer{})
|
||||
c.Assert(err, gc.ErrorMatches, `context already has a writer named "default"`)
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestReplaceDefaultWriter(c *gc.C) {
|
||||
oldWriter, err := loggo.ReplaceDefaultWriter(&writer{})
|
||||
c.Assert(oldWriter, gc.NotNil)
|
||||
c.Assert(err, gc.IsNil)
|
||||
c.Assert(loggo.DefaultContext().WriterNames(), gc.DeepEquals, []string{"default"})
|
||||
}
|
||||
|
||||
func (*GlobalSuite) TestRemoveWriter(c *gc.C) {
|
||||
oldWriter, err := loggo.RemoveWriter("default")
|
||||
c.Assert(oldWriter, gc.NotNil)
|
||||
c.Assert(err, gc.IsNil)
|
||||
c.Assert(loggo.DefaultContext().WriterNames(), gc.HasLen, 0)
|
||||
}
|
102
vendor/github.com/juju/loggo/level.go
generated
vendored
Normal file
102
vendor/github.com/juju/loggo/level.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// The severity levels. Higher values are more considered more
|
||||
// important.
|
||||
const (
|
||||
UNSPECIFIED Level = iota
|
||||
TRACE
|
||||
DEBUG
|
||||
INFO
|
||||
WARNING
|
||||
ERROR
|
||||
CRITICAL
|
||||
)
|
||||
|
||||
// Level holds a severity level.
|
||||
type Level uint32
|
||||
|
||||
// ParseLevel converts a string representation of a logging level to a
|
||||
// Level. It returns the level and whether it was valid or not.
|
||||
func ParseLevel(level string) (Level, bool) {
|
||||
level = strings.ToUpper(level)
|
||||
switch level {
|
||||
case "UNSPECIFIED":
|
||||
return UNSPECIFIED, true
|
||||
case "TRACE":
|
||||
return TRACE, true
|
||||
case "DEBUG":
|
||||
return DEBUG, true
|
||||
case "INFO":
|
||||
return INFO, true
|
||||
case "WARN", "WARNING":
|
||||
return WARNING, true
|
||||
case "ERROR":
|
||||
return ERROR, true
|
||||
case "CRITICAL":
|
||||
return CRITICAL, true
|
||||
default:
|
||||
return UNSPECIFIED, false
|
||||
}
|
||||
}
|
||||
|
||||
// String implements Stringer.
|
||||
func (level Level) String() string {
|
||||
switch level {
|
||||
case UNSPECIFIED:
|
||||
return "UNSPECIFIED"
|
||||
case TRACE:
|
||||
return "TRACE"
|
||||
case DEBUG:
|
||||
return "DEBUG"
|
||||
case INFO:
|
||||
return "INFO"
|
||||
case WARNING:
|
||||
return "WARNING"
|
||||
case ERROR:
|
||||
return "ERROR"
|
||||
case CRITICAL:
|
||||
return "CRITICAL"
|
||||
default:
|
||||
return "<unknown>"
|
||||
}
|
||||
}
|
||||
|
||||
// Short returns a five character string to use in
|
||||
// aligned logging output.
|
||||
func (level Level) Short() string {
|
||||
switch level {
|
||||
case TRACE:
|
||||
return "TRACE"
|
||||
case DEBUG:
|
||||
return "DEBUG"
|
||||
case INFO:
|
||||
return "INFO "
|
||||
case WARNING:
|
||||
return "WARN "
|
||||
case ERROR:
|
||||
return "ERROR"
|
||||
case CRITICAL:
|
||||
return "CRITC"
|
||||
default:
|
||||
return " "
|
||||
}
|
||||
}
|
||||
|
||||
// get atomically gets the value of the given level.
|
||||
func (level *Level) get() Level {
|
||||
return Level(atomic.LoadUint32((*uint32)(level)))
|
||||
}
|
||||
|
||||
// set atomically sets the value of the receiver
|
||||
// to the given level.
|
||||
func (level *Level) set(newLevel Level) {
|
||||
atomic.StoreUint32((*uint32)(level), uint32(newLevel))
|
||||
}
|
96
vendor/github.com/juju/loggo/level_test.go
generated
vendored
Normal file
96
vendor/github.com/juju/loggo/level_test.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/loggo"
|
||||
)
|
||||
|
||||
type LevelSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&LevelSuite{})
|
||||
|
||||
var parseLevelTests = []struct {
|
||||
str string
|
||||
level loggo.Level
|
||||
fail bool
|
||||
}{{
|
||||
str: "trace",
|
||||
level: loggo.TRACE,
|
||||
}, {
|
||||
str: "TrAce",
|
||||
level: loggo.TRACE,
|
||||
}, {
|
||||
str: "TRACE",
|
||||
level: loggo.TRACE,
|
||||
}, {
|
||||
str: "debug",
|
||||
level: loggo.DEBUG,
|
||||
}, {
|
||||
str: "DEBUG",
|
||||
level: loggo.DEBUG,
|
||||
}, {
|
||||
str: "info",
|
||||
level: loggo.INFO,
|
||||
}, {
|
||||
str: "INFO",
|
||||
level: loggo.INFO,
|
||||
}, {
|
||||
str: "warn",
|
||||
level: loggo.WARNING,
|
||||
}, {
|
||||
str: "WARN",
|
||||
level: loggo.WARNING,
|
||||
}, {
|
||||
str: "warning",
|
||||
level: loggo.WARNING,
|
||||
}, {
|
||||
str: "WARNING",
|
||||
level: loggo.WARNING,
|
||||
}, {
|
||||
str: "error",
|
||||
level: loggo.ERROR,
|
||||
}, {
|
||||
str: "ERROR",
|
||||
level: loggo.ERROR,
|
||||
}, {
|
||||
str: "critical",
|
||||
level: loggo.CRITICAL,
|
||||
}, {
|
||||
str: "not_specified",
|
||||
fail: true,
|
||||
}, {
|
||||
str: "other",
|
||||
fail: true,
|
||||
}, {
|
||||
str: "",
|
||||
fail: true,
|
||||
}}
|
||||
|
||||
func (s *LevelSuite) TestParseLevel(c *gc.C) {
|
||||
for _, test := range parseLevelTests {
|
||||
level, ok := loggo.ParseLevel(test.str)
|
||||
c.Assert(level, gc.Equals, test.level)
|
||||
c.Assert(ok, gc.Equals, !test.fail)
|
||||
}
|
||||
}
|
||||
|
||||
var levelStringValueTests = map[loggo.Level]string{
|
||||
loggo.UNSPECIFIED: "UNSPECIFIED",
|
||||
loggo.DEBUG: "DEBUG",
|
||||
loggo.TRACE: "TRACE",
|
||||
loggo.INFO: "INFO",
|
||||
loggo.WARNING: "WARNING",
|
||||
loggo.ERROR: "ERROR",
|
||||
loggo.CRITICAL: "CRITICAL",
|
||||
loggo.Level(42): "<unknown>", // other values are unknown
|
||||
}
|
||||
|
||||
func (s *LevelSuite) TestLevelStringValue(c *gc.C) {
|
||||
for level, str := range levelStringValueTests {
|
||||
c.Assert(level.String(), gc.Equals, str)
|
||||
}
|
||||
}
|
176
vendor/github.com/juju/loggo/logger.go
generated
vendored
Normal file
176
vendor/github.com/juju/loggo/logger.go
generated
vendored
Normal file
|
@ -0,0 +1,176 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Logger represents a logging module. It has an associated logging
|
||||
// level which can be changed; messages of lesser severity will
|
||||
// be dropped. Loggers have a hierarchical relationship - see
|
||||
// the package documentation.
|
||||
//
|
||||
// The zero Logger value is usable - any messages logged
|
||||
// to it will be sent to the root Logger.
|
||||
type Logger struct {
|
||||
impl *module
|
||||
}
|
||||
|
||||
func (logger Logger) getModule() *module {
|
||||
if logger.impl == nil {
|
||||
return defaultContext.root
|
||||
}
|
||||
return logger.impl
|
||||
}
|
||||
|
||||
// Name returns the logger's module name.
|
||||
func (logger Logger) Name() string {
|
||||
return logger.getModule().Name()
|
||||
}
|
||||
|
||||
// LogLevel returns the configured min log level of the logger.
|
||||
func (logger Logger) LogLevel() Level {
|
||||
return logger.getModule().level
|
||||
}
|
||||
|
||||
// EffectiveLogLevel returns the effective min log level of
|
||||
// the receiver - that is, messages with a lesser severity
|
||||
// level will be discarded.
|
||||
//
|
||||
// If the log level of the receiver is unspecified,
|
||||
// it will be taken from the effective log level of its
|
||||
// parent.
|
||||
func (logger Logger) EffectiveLogLevel() Level {
|
||||
return logger.getModule().getEffectiveLogLevel()
|
||||
}
|
||||
|
||||
// SetLogLevel sets the severity level of the given logger.
|
||||
// The root logger cannot be set to UNSPECIFIED level.
|
||||
// See EffectiveLogLevel for how this affects the
|
||||
// actual messages logged.
|
||||
func (logger Logger) SetLogLevel(level Level) {
|
||||
logger.getModule().setLevel(level)
|
||||
}
|
||||
|
||||
// Logf logs a printf-formatted message at the given level.
|
||||
// A message will be discarded if level is less than the
|
||||
// the effective log level of the logger.
|
||||
// Note that the writers may also filter out messages that
|
||||
// are less than their registered minimum severity level.
|
||||
func (logger Logger) Logf(level Level, message string, args ...interface{}) {
|
||||
logger.LogCallf(2, level, message, args...)
|
||||
}
|
||||
|
||||
// LogCallf logs a printf-formatted message at the given level.
|
||||
// The location of the call is indicated by the calldepth argument.
|
||||
// A calldepth of 1 means the function that called this function.
|
||||
// A message will be discarded if level is less than the
|
||||
// the effective log level of the logger.
|
||||
// Note that the writers may also filter out messages that
|
||||
// are less than their registered minimum severity level.
|
||||
func (logger Logger) LogCallf(calldepth int, level Level, message string, args ...interface{}) {
|
||||
module := logger.getModule()
|
||||
if !module.willWrite(level) {
|
||||
return
|
||||
}
|
||||
// Gather time, and filename, line number.
|
||||
now := time.Now() // get this early.
|
||||
// Param to Caller is the call depth. Since this method is called from
|
||||
// the Logger methods, we want the place that those were called from.
|
||||
_, file, line, ok := runtime.Caller(calldepth + 1)
|
||||
if !ok {
|
||||
file = "???"
|
||||
line = 0
|
||||
}
|
||||
// Trim newline off format string, following usual
|
||||
// Go logging conventions.
|
||||
if len(message) > 0 && message[len(message)-1] == '\n' {
|
||||
message = message[0 : len(message)-1]
|
||||
}
|
||||
|
||||
// To avoid having a proliferation of Info/Infof methods,
|
||||
// only use Sprintf if there are any args, and rely on the
|
||||
// `go vet` tool for the obvious cases where someone has forgotten
|
||||
// to provide an arg.
|
||||
formattedMessage := message
|
||||
if len(args) > 0 {
|
||||
formattedMessage = fmt.Sprintf(message, args...)
|
||||
}
|
||||
module.write(Entry{
|
||||
Level: level,
|
||||
Filename: file,
|
||||
Line: line,
|
||||
Timestamp: now,
|
||||
Message: formattedMessage,
|
||||
})
|
||||
}
|
||||
|
||||
// Criticalf logs the printf-formatted message at critical level.
|
||||
func (logger Logger) Criticalf(message string, args ...interface{}) {
|
||||
logger.Logf(CRITICAL, message, args...)
|
||||
}
|
||||
|
||||
// Errorf logs the printf-formatted message at error level.
|
||||
func (logger Logger) Errorf(message string, args ...interface{}) {
|
||||
logger.Logf(ERROR, message, args...)
|
||||
}
|
||||
|
||||
// Warningf logs the printf-formatted message at warning level.
|
||||
func (logger Logger) Warningf(message string, args ...interface{}) {
|
||||
logger.Logf(WARNING, message, args...)
|
||||
}
|
||||
|
||||
// Infof logs the printf-formatted message at info level.
|
||||
func (logger Logger) Infof(message string, args ...interface{}) {
|
||||
logger.Logf(INFO, message, args...)
|
||||
}
|
||||
|
||||
// Debugf logs the printf-formatted message at debug level.
|
||||
func (logger Logger) Debugf(message string, args ...interface{}) {
|
||||
logger.Logf(DEBUG, message, args...)
|
||||
}
|
||||
|
||||
// Tracef logs the printf-formatted message at trace level.
|
||||
func (logger Logger) Tracef(message string, args ...interface{}) {
|
||||
logger.Logf(TRACE, message, args...)
|
||||
}
|
||||
|
||||
// IsLevelEnabled returns whether debugging is enabled
|
||||
// for the given log level.
|
||||
func (logger Logger) IsLevelEnabled(level Level) bool {
|
||||
return logger.getModule().willWrite(level)
|
||||
}
|
||||
|
||||
// IsErrorEnabled returns whether debugging is enabled
|
||||
// at error level.
|
||||
func (logger Logger) IsErrorEnabled() bool {
|
||||
return logger.IsLevelEnabled(ERROR)
|
||||
}
|
||||
|
||||
// IsWarningEnabled returns whether debugging is enabled
|
||||
// at warning level.
|
||||
func (logger Logger) IsWarningEnabled() bool {
|
||||
return logger.IsLevelEnabled(WARNING)
|
||||
}
|
||||
|
||||
// IsInfoEnabled returns whether debugging is enabled
|
||||
// at info level.
|
||||
func (logger Logger) IsInfoEnabled() bool {
|
||||
return logger.IsLevelEnabled(INFO)
|
||||
}
|
||||
|
||||
// IsDebugEnabled returns whether debugging is enabled
|
||||
// at debug level.
|
||||
func (logger Logger) IsDebugEnabled() bool {
|
||||
return logger.IsLevelEnabled(DEBUG)
|
||||
}
|
||||
|
||||
// IsTraceEnabled returns whether debugging is enabled
|
||||
// at trace level.
|
||||
func (logger Logger) IsTraceEnabled() bool {
|
||||
return logger.IsLevelEnabled(TRACE)
|
||||
}
|
139
vendor/github.com/juju/loggo/logger_test.go
generated
vendored
Normal file
139
vendor/github.com/juju/loggo/logger_test.go
generated
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/loggo"
|
||||
)
|
||||
|
||||
type LoggerSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&LoggerSuite{})
|
||||
|
||||
func (*LoggerSuite) SetUpTest(c *gc.C) {
|
||||
loggo.ResetDefaultContext()
|
||||
}
|
||||
|
||||
func (s *LoggerSuite) TestRootLogger(c *gc.C) {
|
||||
root := loggo.Logger{}
|
||||
c.Check(root.Name(), gc.Equals, "<root>")
|
||||
c.Check(root.LogLevel(), gc.Equals, loggo.WARNING)
|
||||
c.Check(root.IsErrorEnabled(), gc.Equals, true)
|
||||
c.Check(root.IsWarningEnabled(), gc.Equals, true)
|
||||
c.Check(root.IsInfoEnabled(), gc.Equals, false)
|
||||
c.Check(root.IsDebugEnabled(), gc.Equals, false)
|
||||
c.Check(root.IsTraceEnabled(), gc.Equals, false)
|
||||
}
|
||||
|
||||
func (s *LoggerSuite) TestSetLevel(c *gc.C) {
|
||||
logger := loggo.GetLogger("testing")
|
||||
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.UNSPECIFIED)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.WARNING)
|
||||
c.Assert(logger.IsErrorEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsWarningEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsInfoEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsDebugEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsTraceEnabled(), gc.Equals, false)
|
||||
logger.SetLogLevel(loggo.TRACE)
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.TRACE)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.TRACE)
|
||||
c.Assert(logger.IsErrorEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsWarningEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsInfoEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsDebugEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsTraceEnabled(), gc.Equals, true)
|
||||
logger.SetLogLevel(loggo.DEBUG)
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.DEBUG)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.DEBUG)
|
||||
c.Assert(logger.IsErrorEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsWarningEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsInfoEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsDebugEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsTraceEnabled(), gc.Equals, false)
|
||||
logger.SetLogLevel(loggo.INFO)
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.INFO)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.INFO)
|
||||
c.Assert(logger.IsErrorEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsWarningEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsInfoEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsDebugEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsTraceEnabled(), gc.Equals, false)
|
||||
logger.SetLogLevel(loggo.WARNING)
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.WARNING)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.WARNING)
|
||||
c.Assert(logger.IsErrorEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsWarningEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsInfoEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsDebugEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsTraceEnabled(), gc.Equals, false)
|
||||
logger.SetLogLevel(loggo.ERROR)
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(logger.IsErrorEnabled(), gc.Equals, true)
|
||||
c.Assert(logger.IsWarningEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsInfoEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsDebugEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsTraceEnabled(), gc.Equals, false)
|
||||
// This is added for completeness, but not really expected to be used.
|
||||
logger.SetLogLevel(loggo.CRITICAL)
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.CRITICAL)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.CRITICAL)
|
||||
c.Assert(logger.IsErrorEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsWarningEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsInfoEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsDebugEnabled(), gc.Equals, false)
|
||||
c.Assert(logger.IsTraceEnabled(), gc.Equals, false)
|
||||
logger.SetLogLevel(loggo.UNSPECIFIED)
|
||||
c.Assert(logger.LogLevel(), gc.Equals, loggo.UNSPECIFIED)
|
||||
c.Assert(logger.EffectiveLogLevel(), gc.Equals, loggo.WARNING)
|
||||
}
|
||||
|
||||
func (s *LoggerSuite) TestModuleLowered(c *gc.C) {
|
||||
logger1 := loggo.GetLogger("TESTING.MODULE")
|
||||
logger2 := loggo.GetLogger("Testing")
|
||||
|
||||
c.Assert(logger1.Name(), gc.Equals, "testing.module")
|
||||
c.Assert(logger2.Name(), gc.Equals, "testing")
|
||||
}
|
||||
|
||||
func (s *LoggerSuite) TestLevelsInherited(c *gc.C) {
|
||||
root := loggo.GetLogger("")
|
||||
first := loggo.GetLogger("first")
|
||||
second := loggo.GetLogger("first.second")
|
||||
|
||||
root.SetLogLevel(loggo.ERROR)
|
||||
c.Assert(root.LogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(root.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(first.LogLevel(), gc.Equals, loggo.UNSPECIFIED)
|
||||
c.Assert(first.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(second.LogLevel(), gc.Equals, loggo.UNSPECIFIED)
|
||||
c.Assert(second.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
|
||||
first.SetLogLevel(loggo.DEBUG)
|
||||
c.Assert(root.LogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(root.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(first.LogLevel(), gc.Equals, loggo.DEBUG)
|
||||
c.Assert(first.EffectiveLogLevel(), gc.Equals, loggo.DEBUG)
|
||||
c.Assert(second.LogLevel(), gc.Equals, loggo.UNSPECIFIED)
|
||||
c.Assert(second.EffectiveLogLevel(), gc.Equals, loggo.DEBUG)
|
||||
|
||||
second.SetLogLevel(loggo.INFO)
|
||||
c.Assert(root.LogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(root.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(first.LogLevel(), gc.Equals, loggo.DEBUG)
|
||||
c.Assert(first.EffectiveLogLevel(), gc.Equals, loggo.DEBUG)
|
||||
c.Assert(second.LogLevel(), gc.Equals, loggo.INFO)
|
||||
c.Assert(second.EffectiveLogLevel(), gc.Equals, loggo.INFO)
|
||||
|
||||
first.SetLogLevel(loggo.UNSPECIFIED)
|
||||
c.Assert(root.LogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(root.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(first.LogLevel(), gc.Equals, loggo.UNSPECIFIED)
|
||||
c.Assert(first.EffectiveLogLevel(), gc.Equals, loggo.ERROR)
|
||||
c.Assert(second.LogLevel(), gc.Equals, loggo.INFO)
|
||||
c.Assert(second.EffectiveLogLevel(), gc.Equals, loggo.INFO)
|
||||
}
|
92
vendor/github.com/juju/loggo/logging_test.go
generated
vendored
Normal file
92
vendor/github.com/juju/loggo/logging_test.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/loggo"
|
||||
)
|
||||
|
||||
type LoggingSuite struct {
|
||||
context *loggo.Context
|
||||
writer *writer
|
||||
logger loggo.Logger
|
||||
}
|
||||
|
||||
var _ = gc.Suite(&LoggingSuite{})
|
||||
|
||||
func (s *LoggingSuite) SetUpTest(c *gc.C) {
|
||||
s.writer = &writer{}
|
||||
s.context = loggo.NewContext(loggo.TRACE)
|
||||
s.context.AddWriter("test", s.writer)
|
||||
s.logger = s.context.GetLogger("test")
|
||||
}
|
||||
|
||||
func (s *LoggingSuite) TestLoggingStrings(c *gc.C) {
|
||||
s.logger.Infof("simple")
|
||||
s.logger.Infof("with args %d", 42)
|
||||
s.logger.Infof("working 100%")
|
||||
s.logger.Infof("missing %s")
|
||||
|
||||
checkLogEntries(c, s.writer.Log(), []loggo.Entry{
|
||||
{Level: loggo.INFO, Module: "test", Message: "simple"},
|
||||
{Level: loggo.INFO, Module: "test", Message: "with args 42"},
|
||||
{Level: loggo.INFO, Module: "test", Message: "working 100%"},
|
||||
{Level: loggo.INFO, Module: "test", Message: "missing %s"},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *LoggingSuite) TestLoggingLimitWarning(c *gc.C) {
|
||||
s.logger.SetLogLevel(loggo.WARNING)
|
||||
start := time.Now()
|
||||
logAllSeverities(s.logger)
|
||||
end := time.Now()
|
||||
entries := s.writer.Log()
|
||||
checkLogEntries(c, entries, []loggo.Entry{
|
||||
{Level: loggo.CRITICAL, Module: "test", Message: "something critical"},
|
||||
{Level: loggo.ERROR, Module: "test", Message: "an error"},
|
||||
{Level: loggo.WARNING, Module: "test", Message: "a warning message"},
|
||||
})
|
||||
|
||||
for _, entry := range entries {
|
||||
c.Check(entry.Timestamp, Between(start, end))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LoggingSuite) TestLocationCapture(c *gc.C) {
|
||||
s.logger.Criticalf("critical message") //tag critical-location
|
||||
s.logger.Errorf("error message") //tag error-location
|
||||
s.logger.Warningf("warning message") //tag warning-location
|
||||
s.logger.Infof("info message") //tag info-location
|
||||
s.logger.Debugf("debug message") //tag debug-location
|
||||
s.logger.Tracef("trace message") //tag trace-location
|
||||
|
||||
log := s.writer.Log()
|
||||
tags := []string{
|
||||
"critical-location",
|
||||
"error-location",
|
||||
"warning-location",
|
||||
"info-location",
|
||||
"debug-location",
|
||||
"trace-location",
|
||||
}
|
||||
c.Assert(log, gc.HasLen, len(tags))
|
||||
for x := range tags {
|
||||
assertLocation(c, log[x], tags[x])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LoggingSuite) TestLogDoesntLogWeirdLevels(c *gc.C) {
|
||||
s.logger.Logf(loggo.UNSPECIFIED, "message")
|
||||
c.Assert(s.writer.Log(), gc.HasLen, 0)
|
||||
|
||||
s.logger.Logf(loggo.Level(42), "message")
|
||||
c.Assert(s.writer.Log(), gc.HasLen, 0)
|
||||
|
||||
s.logger.Logf(loggo.CRITICAL+loggo.Level(1), "message")
|
||||
c.Assert(s.writer.Log(), gc.HasLen, 0)
|
||||
}
|
61
vendor/github.com/juju/loggo/module.go
generated
vendored
Normal file
61
vendor/github.com/juju/loggo/module.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
// Do not change rootName: modules.resolve() will misbehave if it isn't "".
|
||||
const (
|
||||
rootString = "<root>"
|
||||
defaultRootLevel = WARNING
|
||||
defaultLevel = UNSPECIFIED
|
||||
)
|
||||
|
||||
type module struct {
|
||||
name string
|
||||
level Level
|
||||
parent *module
|
||||
context *Context
|
||||
}
|
||||
|
||||
// Name returns the module's name.
|
||||
func (module *module) Name() string {
|
||||
if module.name == "" {
|
||||
return rootString
|
||||
}
|
||||
return module.name
|
||||
}
|
||||
|
||||
func (m *module) willWrite(level Level) bool {
|
||||
if level < TRACE || level > CRITICAL {
|
||||
return false
|
||||
}
|
||||
return level >= m.getEffectiveLogLevel()
|
||||
}
|
||||
|
||||
func (module *module) getEffectiveLogLevel() Level {
|
||||
// Note: the root module is guaranteed to have a
|
||||
// specified logging level, so acts as a suitable sentinel
|
||||
// for this loop.
|
||||
for {
|
||||
if level := module.level.get(); level != UNSPECIFIED {
|
||||
return level
|
||||
}
|
||||
module = module.parent
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// setLevel sets the severity level of the given module.
|
||||
// The root module cannot be set to UNSPECIFIED level.
|
||||
func (module *module) setLevel(level Level) {
|
||||
// The root module can't be unspecified.
|
||||
if module.name == "" && level == UNSPECIFIED {
|
||||
level = WARNING
|
||||
}
|
||||
module.level.set(level)
|
||||
}
|
||||
|
||||
func (m *module) write(entry Entry) {
|
||||
entry.Module = m.name
|
||||
m.context.write(entry)
|
||||
}
|
14
vendor/github.com/juju/loggo/package_test.go
generated
vendored
Normal file
14
vendor/github.com/juju/loggo/package_test.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
gc.TestingT(t)
|
||||
}
|
40
vendor/github.com/juju/loggo/testwriter.go
generated
vendored
Normal file
40
vendor/github.com/juju/loggo/testwriter.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import (
|
||||
"path"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// TestWriter is a useful Writer for testing purposes. Each component of the
|
||||
// logging message is stored in the Log array.
|
||||
type TestWriter struct {
|
||||
mu sync.Mutex
|
||||
log []Entry
|
||||
}
|
||||
|
||||
// Write saves the params as members in the TestLogValues struct appended to the Log array.
|
||||
func (writer *TestWriter) Write(entry Entry) {
|
||||
writer.mu.Lock()
|
||||
defer writer.mu.Unlock()
|
||||
entry.Filename = path.Base(entry.Filename)
|
||||
writer.log = append(writer.log, entry)
|
||||
}
|
||||
|
||||
// Clear removes any saved log messages.
|
||||
func (writer *TestWriter) Clear() {
|
||||
writer.mu.Lock()
|
||||
defer writer.mu.Unlock()
|
||||
writer.log = nil
|
||||
}
|
||||
|
||||
// Log returns a copy of the current logged values.
|
||||
func (writer *TestWriter) Log() []Entry {
|
||||
writer.mu.Lock()
|
||||
defer writer.mu.Unlock()
|
||||
v := make([]Entry, len(writer.log))
|
||||
copy(v, writer.log)
|
||||
return v
|
||||
}
|
68
vendor/github.com/juju/loggo/util_test.go
generated
vendored
Normal file
68
vendor/github.com/juju/loggo/util_test.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2016 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"github.com/juju/loggo"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func init() {
|
||||
setLocationsForTags("logging_test.go")
|
||||
setLocationsForTags("writer_test.go")
|
||||
}
|
||||
|
||||
func assertLocation(c *gc.C, msg loggo.Entry, tag string) {
|
||||
loc := location(tag)
|
||||
c.Assert(msg.Filename, gc.Equals, loc.file)
|
||||
c.Assert(msg.Line, gc.Equals, loc.line)
|
||||
}
|
||||
|
||||
// All this location stuff is to avoid having hard coded line numbers
|
||||
// in the tests. Any line where as a test writer you want to capture the
|
||||
// file and line number, add a comment that has `//tag name` as the end of
|
||||
// the line. The name must be unique across all the tests, and the test
|
||||
// will panic if it is not. This name is then used to read the actual
|
||||
// file and line numbers.
|
||||
|
||||
func location(tag string) Location {
|
||||
loc, ok := tagToLocation[tag]
|
||||
if !ok {
|
||||
panic(fmt.Errorf("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 setLocationsForTags(filename string) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
lines := strings.Split(string(data), "\n")
|
||||
for i, line := range lines {
|
||||
if j := strings.Index(line, "//tag "); j >= 0 {
|
||||
tag := line[j+len("//tag "):]
|
||||
if _, found := tagToLocation[tag]; found {
|
||||
panic(fmt.Errorf("tag %q already processed previously"))
|
||||
}
|
||||
tagToLocation[tag] = Location{file: filename, line: i + 1}
|
||||
}
|
||||
}
|
||||
}
|
70
vendor/github.com/juju/loggo/writer.go
generated
vendored
Normal file
70
vendor/github.com/juju/loggo/writer.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// DefaultWriterName is the name of the default writer for
|
||||
// a Context.
|
||||
const DefaultWriterName = "default"
|
||||
|
||||
// Writer is implemented by any recipient of log messages.
|
||||
type Writer interface {
|
||||
// Write writes a message to the Writer with the given level and module
|
||||
// name. The filename and line hold the file name and line number of the
|
||||
// code that is generating the log message; the time stamp holds the time
|
||||
// the log message was generated, and message holds the log message
|
||||
// itself.
|
||||
Write(entry Entry)
|
||||
}
|
||||
|
||||
// NewMinLevelWriter returns a Writer that will only pass on the Write calls
|
||||
// to the provided writer if the log level is at or above the specified
|
||||
// minimum level.
|
||||
func NewMinimumLevelWriter(writer Writer, minLevel Level) Writer {
|
||||
return &minLevelWriter{
|
||||
writer: writer,
|
||||
level: minLevel,
|
||||
}
|
||||
}
|
||||
|
||||
type minLevelWriter struct {
|
||||
writer Writer
|
||||
level Level
|
||||
}
|
||||
|
||||
// Write writes the log record.
|
||||
func (w minLevelWriter) Write(entry Entry) {
|
||||
if entry.Level < w.level {
|
||||
return
|
||||
}
|
||||
w.writer.Write(entry)
|
||||
}
|
||||
|
||||
type simpleWriter struct {
|
||||
writer io.Writer
|
||||
formatter func(entry Entry) string
|
||||
}
|
||||
|
||||
// NewSimpleWriter returns a new writer that writes log messages to the given
|
||||
// io.Writer formatting the messages with the given formatter.
|
||||
func NewSimpleWriter(writer io.Writer, formatter func(entry Entry) string) Writer {
|
||||
if formatter == nil {
|
||||
formatter = DefaultFormatter
|
||||
}
|
||||
return &simpleWriter{writer, formatter}
|
||||
}
|
||||
|
||||
func (simple *simpleWriter) Write(entry Entry) {
|
||||
logLine := simple.formatter(entry)
|
||||
fmt.Fprintln(simple.writer, logLine)
|
||||
}
|
||||
|
||||
func defaultWriter() Writer {
|
||||
return NewSimpleWriter(os.Stderr, DefaultFormatter)
|
||||
}
|
37
vendor/github.com/juju/loggo/writer_test.go
generated
vendored
Normal file
37
vendor/github.com/juju/loggo/writer_test.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package loggo_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
"github.com/juju/loggo"
|
||||
)
|
||||
|
||||
type SimpleWriterSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&SimpleWriterSuite{})
|
||||
|
||||
func (s *SimpleWriterSuite) TestNewSimpleWriter(c *gc.C) {
|
||||
now := time.Now()
|
||||
formatter := func(entry loggo.Entry) string {
|
||||
return "<< " + entry.Message + " >>"
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
writer := loggo.NewSimpleWriter(buf, formatter)
|
||||
writer.Write(loggo.Entry{
|
||||
Level: loggo.INFO,
|
||||
Module: "test",
|
||||
Filename: "somefile.go",
|
||||
Line: 12,
|
||||
Timestamp: now,
|
||||
Message: "a message",
|
||||
})
|
||||
|
||||
c.Check(buf.String(), gc.Equals, "<< a message >>\n")
|
||||
}
|
27
vendor/github.com/juju/testing/checkers/LICENSE-golang
generated
vendored
Normal file
27
vendor/github.com/juju/testing/checkers/LICENSE-golang
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
117
vendor/github.com/juju/testing/checkers/bool.go
generated
vendored
Normal file
117
vendor/github.com/juju/testing/checkers/bool.go
generated
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2011 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type isTrueChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
// IsTrue checks whether a value has an underlying
|
||||
// boolean type and is true.
|
||||
var IsTrue gc.Checker = &isTrueChecker{
|
||||
&gc.CheckerInfo{Name: "IsTrue", Params: []string{"obtained"}},
|
||||
}
|
||||
|
||||
// IsTrue checks whether a value has an underlying
|
||||
// boolean type and is false.
|
||||
var IsFalse gc.Checker = gc.Not(IsTrue)
|
||||
|
||||
func (checker *isTrueChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
|
||||
value := reflect.ValueOf(params[0])
|
||||
if !value.IsValid() {
|
||||
return false, fmt.Sprintf("expected type bool, received %s", value)
|
||||
}
|
||||
switch value.Kind() {
|
||||
case reflect.Bool:
|
||||
return value.Bool(), ""
|
||||
}
|
||||
|
||||
return false, fmt.Sprintf("expected type bool, received type %s", value.Type())
|
||||
}
|
||||
|
||||
type satisfiesChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
// Satisfies checks whether a value causes the argument
|
||||
// function to return true. The function must be of
|
||||
// type func(T) bool where the value being checked
|
||||
// is assignable to T.
|
||||
var Satisfies gc.Checker = &satisfiesChecker{
|
||||
&gc.CheckerInfo{
|
||||
Name: "Satisfies",
|
||||
Params: []string{"obtained", "func(T) bool"},
|
||||
},
|
||||
}
|
||||
|
||||
func (checker *satisfiesChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
f := reflect.ValueOf(params[1])
|
||||
ft := f.Type()
|
||||
if ft.Kind() != reflect.Func ||
|
||||
ft.NumIn() != 1 ||
|
||||
ft.NumOut() != 1 ||
|
||||
ft.Out(0) != reflect.TypeOf(true) {
|
||||
return false, fmt.Sprintf("expected func(T) bool, got %s", ft)
|
||||
}
|
||||
v := reflect.ValueOf(params[0])
|
||||
if !v.IsValid() {
|
||||
if !canBeNil(ft.In(0)) {
|
||||
return false, fmt.Sprintf("cannot assign nil to argument %T", ft.In(0))
|
||||
}
|
||||
v = reflect.Zero(ft.In(0))
|
||||
}
|
||||
if !v.Type().AssignableTo(ft.In(0)) {
|
||||
return false, fmt.Sprintf("wrong argument type %s for %s", v.Type(), ft)
|
||||
}
|
||||
return f.Call([]reflect.Value{v})[0].Interface().(bool), ""
|
||||
}
|
||||
|
||||
func canBeNil(t reflect.Type) bool {
|
||||
switch t.Kind() {
|
||||
case reflect.Chan,
|
||||
reflect.Func,
|
||||
reflect.Interface,
|
||||
reflect.Map,
|
||||
reflect.Ptr,
|
||||
reflect.Slice:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type deepEqualsChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
// The DeepEquals checker verifies that the obtained value is deep-equal to
|
||||
// the expected value. The check will work correctly even when facing
|
||||
// slices, interfaces, and values of different types (which always fail
|
||||
// the test).
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// c.Assert(value, DeepEquals, 42)
|
||||
// c.Assert(array, DeepEquals, []string{"hi", "there"})
|
||||
//
|
||||
// This checker differs from gocheck.DeepEquals in that
|
||||
// it will compare a nil slice equal to an empty slice,
|
||||
// and a nil map equal to an empty map.
|
||||
var DeepEquals gc.Checker = &deepEqualsChecker{
|
||||
&gc.CheckerInfo{Name: "DeepEquals", Params: []string{"obtained", "expected"}},
|
||||
}
|
||||
|
||||
func (checker *deepEqualsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
if ok, err := DeepEqual(params[0], params[1]); !ok {
|
||||
return false, err.Error()
|
||||
}
|
||||
return true, ""
|
||||
}
|
125
vendor/github.com/juju/testing/checkers/bool_test.go
generated
vendored
Normal file
125
vendor/github.com/juju/testing/checkers/bool_test.go
generated
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
// Copyright 2013 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
jc "github.com/juju/testing/checkers"
|
||||
)
|
||||
|
||||
type BoolSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&BoolSuite{})
|
||||
|
||||
func (s *BoolSuite) TestIsTrue(c *gc.C) {
|
||||
c.Assert(true, jc.IsTrue)
|
||||
c.Assert(false, gc.Not(jc.IsTrue))
|
||||
|
||||
result, msg := jc.IsTrue.Check([]interface{}{false}, nil)
|
||||
c.Assert(result, gc.Equals, false)
|
||||
c.Assert(msg, gc.Equals, "")
|
||||
|
||||
result, msg = jc.IsTrue.Check([]interface{}{"foo"}, nil)
|
||||
c.Assert(result, gc.Equals, false)
|
||||
c.Check(msg, gc.Equals, `expected type bool, received type string`)
|
||||
|
||||
result, msg = jc.IsTrue.Check([]interface{}{42}, nil)
|
||||
c.Assert(result, gc.Equals, false)
|
||||
c.Assert(msg, gc.Equals, `expected type bool, received type int`)
|
||||
|
||||
result, msg = jc.IsTrue.Check([]interface{}{nil}, nil)
|
||||
c.Assert(result, gc.Equals, false)
|
||||
c.Assert(msg, gc.Matches, `expected type bool, received <invalid .*Value>`)
|
||||
}
|
||||
|
||||
func (s *BoolSuite) TestIsFalse(c *gc.C) {
|
||||
c.Check(false, jc.IsFalse)
|
||||
c.Check(true, gc.Not(jc.IsFalse))
|
||||
}
|
||||
|
||||
func is42(i int) bool {
|
||||
return i == 42
|
||||
}
|
||||
|
||||
var satisfiesTests = []struct {
|
||||
f interface{}
|
||||
arg interface{}
|
||||
result bool
|
||||
msg string
|
||||
}{{
|
||||
f: is42,
|
||||
arg: 42,
|
||||
result: true,
|
||||
}, {
|
||||
f: is42,
|
||||
arg: 41,
|
||||
result: false,
|
||||
}, {
|
||||
f: is42,
|
||||
arg: "",
|
||||
result: false,
|
||||
msg: "wrong argument type string for func(int) bool",
|
||||
}, {
|
||||
f: os.IsNotExist,
|
||||
arg: errors.New("foo"),
|
||||
result: false,
|
||||
}, {
|
||||
f: os.IsNotExist,
|
||||
arg: os.ErrNotExist,
|
||||
result: true,
|
||||
}, {
|
||||
f: os.IsNotExist,
|
||||
arg: nil,
|
||||
result: false,
|
||||
}, {
|
||||
f: func(chan int) bool { return true },
|
||||
arg: nil,
|
||||
result: true,
|
||||
}, {
|
||||
f: func(func()) bool { return true },
|
||||
arg: nil,
|
||||
result: true,
|
||||
}, {
|
||||
f: func(interface{}) bool { return true },
|
||||
arg: nil,
|
||||
result: true,
|
||||
}, {
|
||||
f: func(map[string]bool) bool { return true },
|
||||
arg: nil,
|
||||
result: true,
|
||||
}, {
|
||||
f: func(*int) bool { return true },
|
||||
arg: nil,
|
||||
result: true,
|
||||
}, {
|
||||
f: func([]string) bool { return true },
|
||||
arg: nil,
|
||||
result: true,
|
||||
}}
|
||||
|
||||
func (s *BoolSuite) TestSatisfies(c *gc.C) {
|
||||
for i, test := range satisfiesTests {
|
||||
c.Logf("test %d. %T %T", i, test.f, test.arg)
|
||||
result, msg := jc.Satisfies.Check([]interface{}{test.arg, test.f}, nil)
|
||||
c.Check(result, gc.Equals, test.result)
|
||||
c.Check(msg, gc.Equals, test.msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BoolSuite) TestDeepEquals(c *gc.C) {
|
||||
for i, test := range deepEqualTests {
|
||||
c.Logf("test %d. %v == %v is %v", i, test.a, test.b, test.eq)
|
||||
result, msg := jc.DeepEquals.Check([]interface{}{test.a, test.b}, nil)
|
||||
c.Check(result, gc.Equals, test.eq)
|
||||
if test.eq {
|
||||
c.Check(msg, gc.Equals, "")
|
||||
} else {
|
||||
c.Check(msg, gc.Not(gc.Equals), "")
|
||||
}
|
||||
}
|
||||
}
|
255
vendor/github.com/juju/testing/checkers/checker.go
generated
vendored
Normal file
255
vendor/github.com/juju/testing/checkers/checker.go
generated
vendored
Normal file
|
@ -0,0 +1,255 @@
|
|||
// Copyright 2012, 2013 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
func TimeBetween(start, end time.Time) gc.Checker {
|
||||
if end.Before(start) {
|
||||
return &timeBetweenChecker{end, start}
|
||||
}
|
||||
return &timeBetweenChecker{start, end}
|
||||
}
|
||||
|
||||
type timeBetweenChecker struct {
|
||||
start, end time.Time
|
||||
}
|
||||
|
||||
func (checker *timeBetweenChecker) Info() *gc.CheckerInfo {
|
||||
info := gc.CheckerInfo{
|
||||
Name: "TimeBetween",
|
||||
Params: []string{"obtained"},
|
||||
}
|
||||
return &info
|
||||
}
|
||||
|
||||
func (checker *timeBetweenChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
when, ok := params[0].(time.Time)
|
||||
if !ok {
|
||||
return false, "obtained value type must be time.Time"
|
||||
}
|
||||
if when.Before(checker.start) {
|
||||
return false, fmt.Sprintf("obtained time %q is before start time %q", when, checker.start)
|
||||
}
|
||||
if when.After(checker.end) {
|
||||
return false, fmt.Sprintf("obtained time %q is after end time %q", when, checker.end)
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// DurationLessThan checker
|
||||
|
||||
type durationLessThanChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var DurationLessThan gc.Checker = &durationLessThanChecker{
|
||||
&gc.CheckerInfo{Name: "DurationLessThan", Params: []string{"obtained", "expected"}},
|
||||
}
|
||||
|
||||
func (checker *durationLessThanChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
obtained, ok := params[0].(time.Duration)
|
||||
if !ok {
|
||||
return false, "obtained value type must be time.Duration"
|
||||
}
|
||||
expected, ok := params[1].(time.Duration)
|
||||
if !ok {
|
||||
return false, "expected value type must be time.Duration"
|
||||
}
|
||||
return obtained.Nanoseconds() < expected.Nanoseconds(), ""
|
||||
}
|
||||
|
||||
// HasPrefix checker for checking strings
|
||||
|
||||
func stringOrStringer(value interface{}) (string, bool) {
|
||||
result, isString := value.(string)
|
||||
if !isString {
|
||||
if stringer, isStringer := value.(fmt.Stringer); isStringer {
|
||||
result, isString = stringer.String(), true
|
||||
}
|
||||
}
|
||||
return result, isString
|
||||
}
|
||||
|
||||
type hasPrefixChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var HasPrefix gc.Checker = &hasPrefixChecker{
|
||||
&gc.CheckerInfo{Name: "HasPrefix", Params: []string{"obtained", "expected"}},
|
||||
}
|
||||
|
||||
func (checker *hasPrefixChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
expected, ok := params[1].(string)
|
||||
if !ok {
|
||||
return false, "expected must be a string"
|
||||
}
|
||||
|
||||
obtained, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
return strings.HasPrefix(obtained, expected), ""
|
||||
}
|
||||
|
||||
return false, "Obtained value is not a string and has no .String()"
|
||||
}
|
||||
|
||||
type hasSuffixChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var HasSuffix gc.Checker = &hasSuffixChecker{
|
||||
&gc.CheckerInfo{Name: "HasSuffix", Params: []string{"obtained", "expected"}},
|
||||
}
|
||||
|
||||
func (checker *hasSuffixChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
expected, ok := params[1].(string)
|
||||
if !ok {
|
||||
return false, "expected must be a string"
|
||||
}
|
||||
|
||||
obtained, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
return strings.HasSuffix(obtained, expected), ""
|
||||
}
|
||||
|
||||
return false, "Obtained value is not a string and has no .String()"
|
||||
}
|
||||
|
||||
type containsChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var Contains gc.Checker = &containsChecker{
|
||||
&gc.CheckerInfo{Name: "Contains", Params: []string{"obtained", "expected"}},
|
||||
}
|
||||
|
||||
func (checker *containsChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
expected, ok := params[1].(string)
|
||||
if !ok {
|
||||
return false, "expected must be a string"
|
||||
}
|
||||
|
||||
obtained, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
return strings.Contains(obtained, expected), ""
|
||||
}
|
||||
|
||||
return false, "Obtained value is not a string and has no .String()"
|
||||
}
|
||||
|
||||
type sameContents struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
// SameContents checks that the obtained slice contains all the values (and
|
||||
// same number of values) of the expected slice and vice versa, without respect
|
||||
// to order or duplicates. Uses DeepEquals on mapped contents to compare.
|
||||
var SameContents gc.Checker = &sameContents{
|
||||
&gc.CheckerInfo{Name: "SameContents", Params: []string{"obtained", "expected"}},
|
||||
}
|
||||
|
||||
func (checker *sameContents) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
if len(params) != 2 {
|
||||
return false, "SameContents expects two slice arguments"
|
||||
}
|
||||
obtained := params[0]
|
||||
expected := params[1]
|
||||
|
||||
tob := reflect.TypeOf(obtained)
|
||||
if tob.Kind() != reflect.Slice {
|
||||
return false, fmt.Sprintf("SameContents expects the obtained value to be a slice, got %q",
|
||||
tob.Kind())
|
||||
}
|
||||
|
||||
texp := reflect.TypeOf(expected)
|
||||
if texp.Kind() != reflect.Slice {
|
||||
return false, fmt.Sprintf("SameContents expects the expected value to be a slice, got %q",
|
||||
texp.Kind())
|
||||
}
|
||||
|
||||
if texp != tob {
|
||||
return false, fmt.Sprintf(
|
||||
"SameContents expects two slices of the same type, expected: %q, got: %q",
|
||||
texp, tob)
|
||||
}
|
||||
|
||||
vexp := reflect.ValueOf(expected)
|
||||
vob := reflect.ValueOf(obtained)
|
||||
length := vexp.Len()
|
||||
|
||||
if vob.Len() != length {
|
||||
// Slice has incorrect number of elements
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// spin up maps with the entries as keys and the counts as values
|
||||
mob := make(map[interface{}]int, length)
|
||||
mexp := make(map[interface{}]int, length)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
mexp[reflect.Indirect(vexp.Index(i)).Interface()]++
|
||||
mob[reflect.Indirect(vob.Index(i)).Interface()]++
|
||||
}
|
||||
|
||||
return reflect.DeepEqual(mob, mexp), ""
|
||||
}
|
||||
|
||||
type errorIsNilChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
// The ErrorIsNil checker tests whether the obtained value is nil.
|
||||
// Explicitly tests against only `nil`.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// c.Assert(err, ErrorIsNil)
|
||||
//
|
||||
var ErrorIsNil gc.Checker = &errorIsNilChecker{
|
||||
&gc.CheckerInfo{Name: "ErrorIsNil", Params: []string{"value"}},
|
||||
}
|
||||
|
||||
type ErrorStacker interface {
|
||||
error
|
||||
StackTrace() []string
|
||||
}
|
||||
|
||||
func (checker *errorIsNilChecker) Check(params []interface{}, names []string) (bool, string) {
|
||||
result, message := errorIsNil(params[0])
|
||||
if !result {
|
||||
if stacker, ok := params[0].(ErrorStacker); ok && message == "" {
|
||||
stack := stacker.StackTrace()
|
||||
if stack != nil {
|
||||
message = "error stack:\n\t" + strings.Join(stack, "\n\t")
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, message
|
||||
}
|
||||
|
||||
func errorIsNil(obtained interface{}) (result bool, message string) {
|
||||
if obtained == nil {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
if _, ok := obtained.(error); !ok {
|
||||
return false, fmt.Sprintf("obtained type (%T) is not an error", obtained)
|
||||
}
|
||||
|
||||
switch v := reflect.ValueOf(obtained); v.Kind() {
|
||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
if v.IsNil() {
|
||||
return false, fmt.Sprintf("value of (%T) is nil, but a typed nil", obtained)
|
||||
}
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
268
vendor/github.com/juju/testing/checkers/checker_test.go
generated
vendored
Normal file
268
vendor/github.com/juju/testing/checkers/checker_test.go
generated
vendored
Normal file
|
@ -0,0 +1,268 @@
|
|||
// Copyright 2013 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
jc "github.com/juju/testing/checkers"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) { gc.TestingT(t) }
|
||||
|
||||
type CheckerSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&CheckerSuite{})
|
||||
|
||||
func (s *CheckerSuite) TestHasPrefix(c *gc.C) {
|
||||
c.Assert("foo bar", jc.HasPrefix, "foo")
|
||||
c.Assert("foo bar", gc.Not(jc.HasPrefix), "omg")
|
||||
}
|
||||
|
||||
func (s *CheckerSuite) TestHasSuffix(c *gc.C) {
|
||||
c.Assert("foo bar", jc.HasSuffix, "bar")
|
||||
c.Assert("foo bar", gc.Not(jc.HasSuffix), "omg")
|
||||
}
|
||||
|
||||
func (s *CheckerSuite) TestContains(c *gc.C) {
|
||||
c.Assert("foo bar baz", jc.Contains, "foo")
|
||||
c.Assert("foo bar baz", jc.Contains, "bar")
|
||||
c.Assert("foo bar baz", jc.Contains, "baz")
|
||||
c.Assert("foo bar baz", gc.Not(jc.Contains), "omg")
|
||||
}
|
||||
|
||||
func (s *CheckerSuite) TestTimeBetween(c *gc.C) {
|
||||
now := time.Now()
|
||||
earlier := now.Add(-1 * time.Second)
|
||||
later := now.Add(time.Second)
|
||||
|
||||
checkOK := func(value interface{}, start, end time.Time) {
|
||||
checker := jc.TimeBetween(start, end)
|
||||
value, msg := checker.Check([]interface{}{value}, nil)
|
||||
c.Check(value, jc.IsTrue)
|
||||
c.Check(msg, gc.Equals, "")
|
||||
}
|
||||
|
||||
checkFails := func(value interface{}, start, end time.Time, match string) {
|
||||
checker := jc.TimeBetween(start, end)
|
||||
value, msg := checker.Check([]interface{}{value}, nil)
|
||||
c.Check(value, jc.IsFalse)
|
||||
c.Check(msg, gc.Matches, match)
|
||||
}
|
||||
|
||||
checkOK(now, earlier, later)
|
||||
// Later can be before earlier...
|
||||
checkOK(now, later, earlier)
|
||||
// check at bounds
|
||||
checkOK(earlier, earlier, later)
|
||||
checkOK(later, earlier, later)
|
||||
|
||||
checkFails(earlier, now, later, `obtained time .* is before start time .*`)
|
||||
checkFails(later, now, earlier, `obtained time .* is after end time .*`)
|
||||
checkFails(42, now, earlier, `obtained value type must be time.Time`)
|
||||
}
|
||||
|
||||
type someStruct struct {
|
||||
a uint
|
||||
}
|
||||
|
||||
func (s *CheckerSuite) TestSameContents(c *gc.C) {
|
||||
//// positive cases ////
|
||||
|
||||
// same
|
||||
c.Check(
|
||||
[]int{1, 2, 3}, jc.SameContents,
|
||||
[]int{1, 2, 3})
|
||||
|
||||
// empty
|
||||
c.Check(
|
||||
[]int{}, jc.SameContents,
|
||||
[]int{})
|
||||
|
||||
// single
|
||||
c.Check(
|
||||
[]int{1}, jc.SameContents,
|
||||
[]int{1})
|
||||
|
||||
// different order
|
||||
c.Check(
|
||||
[]int{1, 2, 3}, jc.SameContents,
|
||||
[]int{3, 2, 1})
|
||||
|
||||
// multiple copies of same
|
||||
c.Check(
|
||||
[]int{1, 1, 2}, jc.SameContents,
|
||||
[]int{2, 1, 1})
|
||||
|
||||
type test struct {
|
||||
s string
|
||||
i int
|
||||
}
|
||||
|
||||
// test structs
|
||||
c.Check(
|
||||
[]test{{"a", 1}, {"b", 2}}, jc.SameContents,
|
||||
[]test{{"b", 2}, {"a", 1}})
|
||||
|
||||
//// negative cases ////
|
||||
|
||||
// different contents
|
||||
c.Check(
|
||||
[]int{1, 3, 2, 5}, gc.Not(jc.SameContents),
|
||||
[]int{5, 2, 3, 4})
|
||||
|
||||
// different size slices
|
||||
c.Check(
|
||||
[]int{1, 2, 3}, gc.Not(jc.SameContents),
|
||||
[]int{1, 2})
|
||||
|
||||
// different counts of same items
|
||||
c.Check(
|
||||
[]int{1, 1, 2}, gc.Not(jc.SameContents),
|
||||
[]int{1, 2, 2})
|
||||
|
||||
// Tests that check that we compare the contents of structs,
|
||||
// that we point to, not just the pointers to them.
|
||||
a1 := someStruct{1}
|
||||
a2 := someStruct{2}
|
||||
a3 := someStruct{3}
|
||||
b1 := someStruct{1}
|
||||
b2 := someStruct{2}
|
||||
// Same order, same contents
|
||||
c.Check(
|
||||
[]*someStruct{&a1, &a2}, jc.SameContents,
|
||||
[]*someStruct{&b1, &b2})
|
||||
|
||||
// Empty vs not
|
||||
c.Check(
|
||||
[]*someStruct{&a1, &a2}, gc.Not(jc.SameContents),
|
||||
[]*someStruct{})
|
||||
|
||||
// Empty vs empty
|
||||
// Same order, same contents
|
||||
c.Check(
|
||||
[]*someStruct{}, jc.SameContents,
|
||||
[]*someStruct{})
|
||||
|
||||
// Different order, same contents
|
||||
c.Check(
|
||||
[]*someStruct{&a1, &a2}, jc.SameContents,
|
||||
[]*someStruct{&b2, &b1})
|
||||
|
||||
// different contents
|
||||
c.Check(
|
||||
[]*someStruct{&a3, &a2}, gc.Not(jc.SameContents),
|
||||
[]*someStruct{&b2, &b1})
|
||||
|
||||
// Different sizes, same contents (duplicate item)
|
||||
c.Check(
|
||||
[]*someStruct{&a1, &a2, &a1}, gc.Not(jc.SameContents),
|
||||
[]*someStruct{&b2, &b1})
|
||||
|
||||
// Different sizes, same contents
|
||||
c.Check(
|
||||
[]*someStruct{&a1, &a1, &a2}, gc.Not(jc.SameContents),
|
||||
[]*someStruct{&b2, &b1})
|
||||
|
||||
// Same sizes, same contents, different quantities
|
||||
c.Check(
|
||||
[]*someStruct{&a1, &a2, &a2}, gc.Not(jc.SameContents),
|
||||
[]*someStruct{&b1, &b1, &b2})
|
||||
|
||||
/// Error cases ///
|
||||
// note: for these tests, we can't use gc.Not, since Not passes the error value through
|
||||
// and checks with a non-empty error always count as failed
|
||||
// Oddly, there doesn't seem to actually be a way to check for an error from a Checker.
|
||||
|
||||
// different type
|
||||
res, err := jc.SameContents.Check([]interface{}{
|
||||
[]string{"1", "2"},
|
||||
[]int{1, 2},
|
||||
}, []string{})
|
||||
c.Check(res, jc.IsFalse)
|
||||
c.Check(err, gc.Not(gc.Equals), "")
|
||||
|
||||
// obtained not a slice
|
||||
res, err = jc.SameContents.Check([]interface{}{
|
||||
"test",
|
||||
[]int{1},
|
||||
}, []string{})
|
||||
c.Check(res, jc.IsFalse)
|
||||
c.Check(err, gc.Not(gc.Equals), "")
|
||||
|
||||
// expected not a slice
|
||||
res, err = jc.SameContents.Check([]interface{}{
|
||||
[]int{1},
|
||||
"test",
|
||||
}, []string{})
|
||||
c.Check(res, jc.IsFalse)
|
||||
c.Check(err, gc.Not(gc.Equals), "")
|
||||
}
|
||||
|
||||
type stack_error struct {
|
||||
message string
|
||||
stack []string
|
||||
}
|
||||
|
||||
type embedded struct {
|
||||
typed *stack_error
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *stack_error) Error() string {
|
||||
return s.message
|
||||
}
|
||||
func (s *stack_error) StackTrace() []string {
|
||||
return s.stack
|
||||
}
|
||||
|
||||
type value_error string
|
||||
|
||||
func (e value_error) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func (s *CheckerSuite) TestErrorIsNil(c *gc.C) {
|
||||
checkOK := func(value interface{}) {
|
||||
value, msg := jc.ErrorIsNil.Check([]interface{}{value}, nil)
|
||||
c.Check(value, jc.IsTrue)
|
||||
c.Check(msg, gc.Equals, "")
|
||||
}
|
||||
|
||||
checkFails := func(value interface{}, match string) {
|
||||
value, msg := jc.ErrorIsNil.Check([]interface{}{value}, nil)
|
||||
c.Check(value, jc.IsFalse)
|
||||
c.Check(msg, gc.Matches, match)
|
||||
}
|
||||
|
||||
var typedNil *stack_error
|
||||
var typedNilAsInterface error = typedNil
|
||||
var nilError error
|
||||
var value value_error
|
||||
var emptyValueErrorAsInterface error = value
|
||||
var embed embedded
|
||||
|
||||
checkOK(nil)
|
||||
checkOK(nilError)
|
||||
checkOK(embed.err)
|
||||
|
||||
checkFails([]string{}, `obtained type \(.*\) is not an error`)
|
||||
checkFails("", `obtained type \(.*\) is not an error`)
|
||||
checkFails(embed.typed, `value of \(.*\) is nil, but a typed nil`)
|
||||
checkFails(typedNilAsInterface, `value of \(.*\) is nil, but a typed nil`)
|
||||
checkFails(fmt.Errorf("an error"), "")
|
||||
checkFails(value, "")
|
||||
checkFails(emptyValueErrorAsInterface, "")
|
||||
|
||||
emptyStack := &stack_error{"message", nil}
|
||||
checkFails(emptyStack, "")
|
||||
|
||||
withStack := &stack_error{"message", []string{
|
||||
"filename:line", "filename2:line2"}}
|
||||
checkFails(withStack, "error stack:\n\tfilename:line\n\tfilename2:line2")
|
||||
}
|
87
vendor/github.com/juju/testing/checkers/codec.go
generated
vendored
Normal file
87
vendor/github.com/juju/testing/checkers/codec.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2012-2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type codecEqualChecker struct {
|
||||
name string
|
||||
marshal func(interface{}) ([]byte, error)
|
||||
unmarshal func([]byte, interface{}) error
|
||||
}
|
||||
|
||||
// BSONEquals defines a checker that checks whether a byte slice, when
|
||||
// unmarshaled as BSON, is equal to the given value. Rather than
|
||||
// unmarshaling into something of the expected body type, we reform
|
||||
// the expected body in BSON and back to interface{} so we can check
|
||||
// the whole content. Otherwise we lose information when unmarshaling.
|
||||
var BSONEquals = &codecEqualChecker{
|
||||
name: "BSONEquals",
|
||||
marshal: bson.Marshal,
|
||||
unmarshal: bson.Unmarshal,
|
||||
}
|
||||
|
||||
// JSONEquals defines a checker that checks whether a byte slice, when
|
||||
// unmarshaled as JSON, is equal to the given value.
|
||||
// Rather than unmarshaling into something of the expected
|
||||
// body type, we reform the expected body in JSON and
|
||||
// back to interface{}, so we can check the whole content.
|
||||
// Otherwise we lose information when unmarshaling.
|
||||
var JSONEquals = &codecEqualChecker{
|
||||
name: "JSONEquals",
|
||||
marshal: json.Marshal,
|
||||
unmarshal: json.Unmarshal,
|
||||
}
|
||||
|
||||
// YAMLEquals defines a checker that checks whether a byte slice, when
|
||||
// unmarshaled as YAML, is equal to the given value.
|
||||
// Rather than unmarshaling into something of the expected
|
||||
// body type, we reform the expected body in YAML and
|
||||
// back to interface{}, so we can check the whole content.
|
||||
// Otherwise we lose information when unmarshaling.
|
||||
var YAMLEquals = &codecEqualChecker{
|
||||
name: "YAMLEquals",
|
||||
marshal: yaml.Marshal,
|
||||
unmarshal: yaml.Unmarshal,
|
||||
}
|
||||
|
||||
func (checker *codecEqualChecker) Info() *gc.CheckerInfo {
|
||||
return &gc.CheckerInfo{
|
||||
Name: checker.name,
|
||||
Params: []string{"obtained", "expected"},
|
||||
}
|
||||
}
|
||||
|
||||
func (checker *codecEqualChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
gotContent, ok := params[0].(string)
|
||||
if !ok {
|
||||
return false, fmt.Sprintf("expected string, got %T", params[0])
|
||||
}
|
||||
expectContent := params[1]
|
||||
expectContentBytes, err := checker.marshal(expectContent)
|
||||
if err != nil {
|
||||
return false, fmt.Sprintf("cannot marshal expected contents: %v", err)
|
||||
}
|
||||
var expectContentVal interface{}
|
||||
if err := checker.unmarshal(expectContentBytes, &expectContentVal); err != nil {
|
||||
return false, fmt.Sprintf("cannot unmarshal expected contents: %v", err)
|
||||
}
|
||||
|
||||
var gotContentVal interface{}
|
||||
if err := checker.unmarshal([]byte(gotContent), &gotContentVal); err != nil {
|
||||
return false, fmt.Sprintf("cannot unmarshal obtained contents: %v; %q", err, gotContent)
|
||||
}
|
||||
|
||||
if ok, err := DeepEqual(gotContentVal, expectContentVal); !ok {
|
||||
return false, err.Error()
|
||||
}
|
||||
return true, ""
|
||||
}
|
157
vendor/github.com/juju/testing/checkers/codec_test.go
generated
vendored
Normal file
157
vendor/github.com/juju/testing/checkers/codec_test.go
generated
vendored
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2014 Canonical Ltd.
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers_test
|
||||
|
||||
import (
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
jc "github.com/juju/testing/checkers"
|
||||
)
|
||||
|
||||
type Inner struct {
|
||||
First string
|
||||
Second int `json:",omitempty" yaml:",omitempty"`
|
||||
Third map[string]bool `json:",omitempty" yaml:",omitempty"`
|
||||
}
|
||||
|
||||
type Outer struct {
|
||||
First float64
|
||||
Second []*Inner `json:"Last,omitempty" yaml:"last,omitempty"`
|
||||
}
|
||||
|
||||
func (s *CheckerSuite) TestJSONEquals(c *gc.C) {
|
||||
tests := []struct {
|
||||
descr string
|
||||
obtained string
|
||||
expected *Outer
|
||||
result bool
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
descr: "very simple",
|
||||
obtained: `{"First": 47.11}`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
descr: "nested",
|
||||
obtained: `{"First": 47.11, "Last": [{"First": "Hello", "Second": 42}]}`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
Second: []*Inner{
|
||||
{First: "Hello", Second: 42},
|
||||
},
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
descr: "nested with newline",
|
||||
obtained: `{"First": 47.11, "Last": [{"First": "Hello", "Second": 42},
|
||||
{"First": "World", "Third": {"T": true, "F": false}}]}`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
Second: []*Inner{
|
||||
{First: "Hello", Second: 42},
|
||||
{First: "World", Third: map[string]bool{
|
||||
"F": false,
|
||||
"T": true,
|
||||
}},
|
||||
},
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
descr: "illegal field",
|
||||
obtained: `{"NotThere": 47.11}`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
},
|
||||
result: false,
|
||||
msg: `mismatch at .*: validity mismatch; .*`,
|
||||
}, {
|
||||
descr: "illegal optained content",
|
||||
obtained: `{"NotThere": `,
|
||||
result: false,
|
||||
msg: `cannot unmarshal obtained contents: unexpected end of JSON input; .*`,
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
c.Logf("test #%d) %s", i, test.descr)
|
||||
result, msg := jc.JSONEquals.Check([]interface{}{test.obtained, test.expected}, nil)
|
||||
c.Check(result, gc.Equals, test.result)
|
||||
c.Check(msg, gc.Matches, test.msg)
|
||||
}
|
||||
|
||||
// Test non-string input.
|
||||
result, msg := jc.JSONEquals.Check([]interface{}{true, true}, nil)
|
||||
c.Check(result, gc.Equals, false)
|
||||
c.Check(msg, gc.Matches, "expected string, got bool")
|
||||
}
|
||||
|
||||
func (s *CheckerSuite) TestYAMLEquals(c *gc.C) {
|
||||
tests := []struct {
|
||||
descr string
|
||||
obtained string
|
||||
expected *Outer
|
||||
result bool
|
||||
msg string
|
||||
}{
|
||||
{
|
||||
descr: "very simple",
|
||||
obtained: `first: 47.11`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
descr: "nested",
|
||||
obtained: `{first: 47.11, last: [{first: 'Hello', second: 42}]}`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
Second: []*Inner{
|
||||
{First: "Hello", Second: 42},
|
||||
},
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
descr: "nested with newline",
|
||||
obtained: `{first: 47.11, last: [{first: 'Hello', second: 42},
|
||||
{first: 'World', third: {t: true, f: false}}]}`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
Second: []*Inner{
|
||||
{First: "Hello", Second: 42},
|
||||
{First: "World", Third: map[string]bool{
|
||||
"f": false,
|
||||
"t": true,
|
||||
}},
|
||||
},
|
||||
},
|
||||
result: true,
|
||||
}, {
|
||||
descr: "illegal field",
|
||||
obtained: `{"NotThere": 47.11}`,
|
||||
expected: &Outer{
|
||||
First: 47.11,
|
||||
},
|
||||
result: false,
|
||||
msg: `mismatch at .*: validity mismatch; .*`,
|
||||
}, {
|
||||
descr: "illegal obtained content",
|
||||
obtained: `{"NotThere": `,
|
||||
result: false,
|
||||
msg: `cannot unmarshal obtained contents: yaml: line 1: .*`,
|
||||
},
|
||||
}
|
||||
for i, test := range tests {
|
||||
c.Logf("test #%d) %s", i, test.descr)
|
||||
result, msg := jc.YAMLEquals.Check([]interface{}{test.obtained, test.expected}, nil)
|
||||
c.Check(result, gc.Equals, test.result)
|
||||
c.Check(msg, gc.Matches, test.msg)
|
||||
}
|
||||
|
||||
// Test non-string input.
|
||||
result, msg := jc.YAMLEquals.Check([]interface{}{true, true}, nil)
|
||||
c.Check(result, gc.Equals, false)
|
||||
c.Check(msg, gc.Matches, "expected string, got bool")
|
||||
}
|
341
vendor/github.com/juju/testing/checkers/deepequal.go
generated
vendored
Normal file
341
vendor/github.com/juju/testing/checkers/deepequal.go
generated
vendored
Normal file
|
@ -0,0 +1,341 @@
|
|||
// Copied with small adaptations from the reflect package in the
|
||||
// Go source tree.
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE-golang file.
|
||||
|
||||
package checkers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var timeType = reflect.TypeOf(time.Time{})
|
||||
|
||||
// During deepValueEqual, must keep track of checks that are
|
||||
// in progress. The comparison algorithm assumes that all
|
||||
// checks in progress are true when it reencounters them.
|
||||
// Visited comparisons are stored in a map indexed by visit.
|
||||
type visit struct {
|
||||
a1 uintptr
|
||||
a2 uintptr
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
type mismatchError struct {
|
||||
v1, v2 reflect.Value
|
||||
path string
|
||||
how string
|
||||
}
|
||||
|
||||
func (err *mismatchError) Error() string {
|
||||
path := err.path
|
||||
if path == "" {
|
||||
path = "top level"
|
||||
}
|
||||
return fmt.Sprintf("mismatch at %s: %s; obtained %#v; expected %#v", path, err.how, printable(err.v1), printable(err.v2))
|
||||
}
|
||||
|
||||
func printable(v reflect.Value) interface{} {
|
||||
vi := interfaceOf(v)
|
||||
switch vi := vi.(type) {
|
||||
case time.Time:
|
||||
return vi.UTC().Format(time.RFC3339Nano)
|
||||
default:
|
||||
return vi
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for deep equality using reflected types. The map argument tracks
|
||||
// comparisons that have already been seen, which allows short circuiting on
|
||||
// recursive types.
|
||||
func deepValueEqual(path string, v1, v2 reflect.Value, visited map[visit]bool, depth int) (ok bool, err error) {
|
||||
errorf := func(f string, a ...interface{}) error {
|
||||
return &mismatchError{
|
||||
v1: v1,
|
||||
v2: v2,
|
||||
path: path,
|
||||
how: fmt.Sprintf(f, a...),
|
||||
}
|
||||
}
|
||||
if !v1.IsValid() || !v2.IsValid() {
|
||||
if v1.IsValid() == v2.IsValid() {
|
||||
return true, nil
|
||||
}
|
||||
return false, errorf("validity mismatch")
|
||||
}
|
||||
if v1.Type() != v2.Type() {
|
||||
return false, errorf("type mismatch %s vs %s", v1.Type(), v2.Type())
|
||||
}
|
||||
|
||||
// if depth > 10 { panic("deepValueEqual") } // for debugging
|
||||
hard := func(k reflect.Kind) bool {
|
||||
switch k {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.Struct:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if v1.CanAddr() && v2.CanAddr() && hard(v1.Kind()) {
|
||||
addr1 := v1.UnsafeAddr()
|
||||
addr2 := v2.UnsafeAddr()
|
||||
if addr1 > addr2 {
|
||||
// Canonicalize order to reduce number of entries in visited.
|
||||
addr1, addr2 = addr2, addr1
|
||||
}
|
||||
|
||||
// Short circuit if references are identical ...
|
||||
if addr1 == addr2 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// ... or already seen
|
||||
typ := v1.Type()
|
||||
v := visit{addr1, addr2, typ}
|
||||
if visited[v] {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Remember for later.
|
||||
visited[v] = true
|
||||
}
|
||||
|
||||
switch v1.Kind() {
|
||||
case reflect.Array:
|
||||
if v1.Len() != v2.Len() {
|
||||
// can't happen!
|
||||
return false, errorf("length mismatch, %d vs %d", v1.Len(), v2.Len())
|
||||
}
|
||||
for i := 0; i < v1.Len(); i++ {
|
||||
if ok, err := deepValueEqual(
|
||||
fmt.Sprintf("%s[%d]", path, i),
|
||||
v1.Index(i), v2.Index(i), visited, depth+1); !ok {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Slice:
|
||||
// We treat a nil slice the same as an empty slice.
|
||||
if v1.Len() != v2.Len() {
|
||||
return false, errorf("length mismatch, %d vs %d", v1.Len(), v2.Len())
|
||||
}
|
||||
if v1.Pointer() == v2.Pointer() {
|
||||
return true, nil
|
||||
}
|
||||
for i := 0; i < v1.Len(); i++ {
|
||||
if ok, err := deepValueEqual(
|
||||
fmt.Sprintf("%s[%d]", path, i),
|
||||
v1.Index(i), v2.Index(i), visited, depth+1); !ok {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Interface:
|
||||
if v1.IsNil() || v2.IsNil() {
|
||||
if v1.IsNil() != v2.IsNil() {
|
||||
return false, errorf("nil vs non-nil interface mismatch")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
return deepValueEqual(path, v1.Elem(), v2.Elem(), visited, depth+1)
|
||||
case reflect.Ptr:
|
||||
return deepValueEqual("(*"+path+")", v1.Elem(), v2.Elem(), visited, depth+1)
|
||||
case reflect.Struct:
|
||||
if v1.Type() == timeType {
|
||||
// Special case for time - we ignore the time zone.
|
||||
t1 := interfaceOf(v1).(time.Time)
|
||||
t2 := interfaceOf(v2).(time.Time)
|
||||
if t1.Equal(t2) {
|
||||
return true, nil
|
||||
}
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
for i, n := 0, v1.NumField(); i < n; i++ {
|
||||
path := path + "." + v1.Type().Field(i).Name
|
||||
if ok, err := deepValueEqual(path, v1.Field(i), v2.Field(i), visited, depth+1); !ok {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Map:
|
||||
if v1.IsNil() != v2.IsNil() {
|
||||
return false, errorf("nil vs non-nil mismatch")
|
||||
}
|
||||
if v1.Len() != v2.Len() {
|
||||
return false, errorf("length mismatch, %d vs %d", v1.Len(), v2.Len())
|
||||
}
|
||||
if v1.Pointer() == v2.Pointer() {
|
||||
return true, nil
|
||||
}
|
||||
for _, k := range v1.MapKeys() {
|
||||
var p string
|
||||
if k.CanInterface() {
|
||||
p = path + "[" + fmt.Sprintf("%#v", k.Interface()) + "]"
|
||||
} else {
|
||||
p = path + "[someKey]"
|
||||
}
|
||||
if ok, err := deepValueEqual(p, v1.MapIndex(k), v2.MapIndex(k), visited, depth+1); !ok {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Func:
|
||||
if v1.IsNil() && v2.IsNil() {
|
||||
return true, nil
|
||||
}
|
||||
// Can't do better than this:
|
||||
return false, errorf("non-nil functions")
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
if v1.Int() != v2.Int() {
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
if v1.Uint() != v2.Uint() {
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Float32, reflect.Float64:
|
||||
if v1.Float() != v2.Float() {
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
if v1.Complex() != v2.Complex() {
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Bool:
|
||||
if v1.Bool() != v2.Bool() {
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
return true, nil
|
||||
case reflect.String:
|
||||
if v1.String() != v2.String() {
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
return true, nil
|
||||
case reflect.Chan, reflect.UnsafePointer:
|
||||
if v1.Pointer() != v2.Pointer() {
|
||||
return false, errorf("unequal")
|
||||
}
|
||||
return true, nil
|
||||
default:
|
||||
panic("unexpected type " + v1.Type().String())
|
||||
}
|
||||
}
|
||||
|
||||
// DeepEqual tests for deep equality. It uses normal == equality where
|
||||
// possible but will scan elements of arrays, slices, maps, and fields
|
||||
// of structs. In maps, keys are compared with == but elements use deep
|
||||
// equality. DeepEqual correctly handles recursive types. Functions are
|
||||
// equal only if they are both nil.
|
||||
//
|
||||
// DeepEqual differs from reflect.DeepEqual in two ways:
|
||||
// - an empty slice is considered equal to a nil slice.
|
||||
// - two time.Time values that represent the same instant
|
||||
// but with different time zones are considered equal.
|
||||
//
|
||||
// If the two values compare unequal, the resulting error holds the
|
||||
// first difference encountered.
|
||||
func DeepEqual(a1, a2 interface{}) (bool, error) {
|
||||
errorf := func(f string, a ...interface{}) error {
|
||||
return &mismatchError{
|
||||
v1: reflect.ValueOf(a1),
|
||||
v2: reflect.ValueOf(a2),
|
||||
path: "",
|
||||
how: fmt.Sprintf(f, a...),
|
||||
}
|
||||
}
|
||||
if a1 == nil || a2 == nil {
|
||||
if a1 == a2 {
|
||||
return true, nil
|
||||
}
|
||||
return false, errorf("nil vs non-nil mismatch")
|
||||
}
|
||||
v1 := reflect.ValueOf(a1)
|
||||
v2 := reflect.ValueOf(a2)
|
||||
if v1.Type() != v2.Type() {
|
||||
return false, errorf("type mismatch %s vs %s", v1.Type(), v2.Type())
|
||||
}
|
||||
return deepValueEqual("", v1, v2, make(map[visit]bool), 0)
|
||||
}
|
||||
|
||||
// interfaceOf returns v.Interface() even if v.CanInterface() == false.
|
||||
// This enables us to call fmt.Printf on a value even if it's derived
|
||||
// from inside an unexported field.
|
||||
// See https://code.google.com/p/go/issues/detail?id=8965
|
||||
// for a possible future alternative to this hack.
|
||||
func interfaceOf(v reflect.Value) interface{} {
|
||||
if !v.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return bypassCanInterface(v).Interface()
|
||||
}
|
||||
|
||||
type flag uintptr
|
||||
|
||||
var flagRO flag
|
||||
|
||||
// constants copied from reflect/value.go
|
||||
const (
|
||||
// The value of flagRO up to and including Go 1.3.
|
||||
flagRO1p3 = 1 << 0
|
||||
|
||||
// The value of flagRO from Go 1.4.
|
||||
flagRO1p4 = 1 << 5
|
||||
)
|
||||
|
||||
var flagValOffset = func() uintptr {
|
||||
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||
if !ok {
|
||||
panic("reflect.Value has no flag field")
|
||||
}
|
||||
return field.Offset
|
||||
}()
|
||||
|
||||
func flagField(v *reflect.Value) *flag {
|
||||
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
|
||||
}
|
||||
|
||||
// bypassCanInterface returns a version of v that
|
||||
// bypasses the CanInterface check.
|
||||
func bypassCanInterface(v reflect.Value) reflect.Value {
|
||||
if !v.IsValid() || v.CanInterface() {
|
||||
return v
|
||||
}
|
||||
*flagField(&v) &^= flagRO
|
||||
return v
|
||||
}
|
||||
|
||||
// Sanity checks against future reflect package changes
|
||||
// to the type or semantics of the Value.flag field.
|
||||
func init() {
|
||||
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||
if !ok {
|
||||
panic("reflect.Value has no flag field")
|
||||
}
|
||||
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
|
||||
panic("reflect.Value flag field has changed kind")
|
||||
}
|
||||
var t struct {
|
||||
a int
|
||||
A int
|
||||
}
|
||||
vA := reflect.ValueOf(t).FieldByName("A")
|
||||
va := reflect.ValueOf(t).FieldByName("a")
|
||||
flagA := *flagField(&vA)
|
||||
flaga := *flagField(&va)
|
||||
|
||||
// Infer flagRO from the difference between the flags
|
||||
// for the (otherwise identical) fields in t.
|
||||
flagRO = flagA ^ flaga
|
||||
if flagRO != flagRO1p3 && flagRO != flagRO1p4 {
|
||||
panic("reflect.Value read-only flag has changed semantics")
|
||||
}
|
||||
}
|
188
vendor/github.com/juju/testing/checkers/deepequal_test.go
generated
vendored
Normal file
188
vendor/github.com/juju/testing/checkers/deepequal_test.go
generated
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
// Copied with small adaptations from the reflect package in the
|
||||
// Go source tree. We use testing rather than gocheck to preserve
|
||||
// as much source equivalence as possible.
|
||||
|
||||
// TODO tests for error messages
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE-golang file.
|
||||
|
||||
package checkers_test
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/juju/testing/checkers"
|
||||
)
|
||||
|
||||
func deepEqual(a1, a2 interface{}) bool {
|
||||
ok, _ := checkers.DeepEqual(a1, a2)
|
||||
return ok
|
||||
}
|
||||
|
||||
type Basic struct {
|
||||
x int
|
||||
y float32
|
||||
}
|
||||
|
||||
type NotBasic Basic
|
||||
|
||||
type DeepEqualTest struct {
|
||||
a, b interface{}
|
||||
eq bool
|
||||
msg string
|
||||
}
|
||||
|
||||
// Simple functions for DeepEqual tests.
|
||||
var (
|
||||
fn1 func() // nil.
|
||||
fn2 func() // nil.
|
||||
fn3 = func() { fn1() } // Not nil.
|
||||
)
|
||||
|
||||
var deepEqualTests = []DeepEqualTest{
|
||||
// Equalities
|
||||
{nil, nil, true, ""},
|
||||
{1, 1, true, ""},
|
||||
{int32(1), int32(1), true, ""},
|
||||
{0.5, 0.5, true, ""},
|
||||
{float32(0.5), float32(0.5), true, ""},
|
||||
{"hello", "hello", true, ""},
|
||||
{make([]int, 10), make([]int, 10), true, ""},
|
||||
{&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true, ""},
|
||||
{Basic{1, 0.5}, Basic{1, 0.5}, true, ""},
|
||||
{error(nil), error(nil), true, ""},
|
||||
{map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true, ""},
|
||||
{fn1, fn2, true, ""},
|
||||
{time.Unix(0, 0), time.Unix(0, 0), true, ""},
|
||||
// Same time from different zones (difference from normal DeepEqual)
|
||||
{time.Unix(0, 0).UTC(), time.Unix(0, 0).In(time.FixedZone("FOO", 60*60)), true, ""},
|
||||
|
||||
// Inequalities
|
||||
{1, 2, false, `mismatch at top level: unequal; obtained 1; expected 2`},
|
||||
{int32(1), int32(2), false, `mismatch at top level: unequal; obtained 1; expected 2`},
|
||||
{0.5, 0.6, false, `mismatch at top level: unequal; obtained 0\.5; expected 0\.6`},
|
||||
{float32(0.5), float32(0.6), false, `mismatch at top level: unequal; obtained 0\.5; expected 0\.6`},
|
||||
{"hello", "hey", false, `mismatch at top level: unequal; obtained "hello"; expected "hey"`},
|
||||
{make([]int, 10), make([]int, 11), false, `mismatch at top level: length mismatch, 10 vs 11; obtained \[\]int\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0\}; expected \[\]int\{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\}`},
|
||||
{&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false, `mismatch at \(\*\)\[2\]: unequal; obtained 3; expected 4`},
|
||||
{Basic{1, 0.5}, Basic{1, 0.6}, false, `mismatch at \.y: unequal; obtained 0\.5; expected 0\.6`},
|
||||
{Basic{1, 0}, Basic{2, 0}, false, `mismatch at \.x: unequal; obtained 1; expected 2`},
|
||||
{map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false, `mismatch at \[3\]: validity mismatch; obtained "two"; expected <nil>`},
|
||||
{map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false, `mismatch at \[2\]: unequal; obtained "txo"; expected "two"`},
|
||||
{map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false, `mismatch at top level: length mismatch, 1 vs 2; obtained map\[int\]string\{1:"one"\}; expected map\[int\]string\{.*\}`},
|
||||
{map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false, `mismatch at top level: length mismatch, 2 vs 1; obtained map\[int\]string\{.*\}; expected map\[int\]string\{1:"one"\}`},
|
||||
{nil, 1, false, `mismatch at top level: nil vs non-nil mismatch; obtained <nil>; expected 1`},
|
||||
{1, nil, false, `mismatch at top level: nil vs non-nil mismatch; obtained 1; expected <nil>`},
|
||||
{fn1, fn3, false, `mismatch at top level: non-nil functions; obtained \(func\(\)\)\(nil\); expected \(func\(\)\)\(0x[0-9a-f]+\)`},
|
||||
{fn3, fn3, false, `mismatch at top level: non-nil functions; obtained \(func\(\)\)\(0x[0-9a-f]+\); expected \(func\(\)\)\(0x[0-9a-f]+\)`},
|
||||
{[]interface{}{nil}, []interface{}{"a"}, false, `mismatch at \[0\]: nil vs non-nil interface mismatch`},
|
||||
|
||||
// Nil vs empty: they're the same (difference from normal DeepEqual)
|
||||
{[]int{}, []int(nil), true, ""},
|
||||
{[]int{}, []int{}, true, ""},
|
||||
{[]int(nil), []int(nil), true, ""},
|
||||
|
||||
// Mismatched types
|
||||
{1, 1.0, false, `mismatch at top level: type mismatch int vs float64; obtained 1; expected 1`},
|
||||
{int32(1), int64(1), false, `mismatch at top level: type mismatch int32 vs int64; obtained 1; expected 1`},
|
||||
{0.5, "hello", false, `mismatch at top level: type mismatch float64 vs string; obtained 0\.5; expected "hello"`},
|
||||
{[]int{1, 2, 3}, [3]int{1, 2, 3}, false, `mismatch at top level: type mismatch \[\]int vs \[3\]int; obtained \[\]int\{1, 2, 3\}; expected \[3\]int\{1, 2, 3\}`},
|
||||
{&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false, `mismatch at \(\*\)\[2\]: type mismatch int vs string; obtained 4; expected "s"`},
|
||||
{Basic{1, 0.5}, NotBasic{1, 0.5}, false, `mismatch at top level: type mismatch checkers_test\.Basic vs checkers_test\.NotBasic; obtained checkers_test\.Basic\{x:1, y:0\.5\}; expected checkers_test\.NotBasic\{x:1, y:0\.5\}`},
|
||||
{time.Unix(0, 0).UTC(), time.Unix(0, 0).In(time.FixedZone("FOO", 60*60)).Add(1), false, `mismatch at top level: unequal; obtained "1970-01-01T00:00:00Z"; expected "1970-01-01T00:00:00.000000001Z"`},
|
||||
{time.Unix(0, 0).UTC(), time.Unix(0, 0).Add(1), false, `mismatch at top level: unequal; obtained "1970-01-01T00:00:00Z"; expected "1970-01-01T00:00:00.000000001Z"`},
|
||||
|
||||
{
|
||||
map[uint]string{1: "one", 2: "two"},
|
||||
map[int]string{2: "two", 1: "one"},
|
||||
false,
|
||||
`mismatch at top level: type mismatch map\[uint\]string vs map\[int\]string; obtained map\[uint\]string\{.*\}; expected map\[int\]string\{.*\}`,
|
||||
},
|
||||
}
|
||||
|
||||
func TestDeepEqual(t *testing.T) {
|
||||
for _, test := range deepEqualTests {
|
||||
r, err := checkers.DeepEqual(test.a, test.b)
|
||||
if r != test.eq {
|
||||
t.Errorf("deepEqual(%v, %v) = %v, want %v", test.a, test.b, r, test.eq)
|
||||
}
|
||||
if test.eq {
|
||||
if err != nil {
|
||||
t.Errorf("deepEqual(%v, %v): unexpected error message %q when equal", test.a, test.b, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
t.Errorf("deepEqual(%v, %v); mismatch but nil error", test.a, test.b)
|
||||
continue
|
||||
}
|
||||
if ok, _ := regexp.MatchString(test.msg, err.Error()); !ok {
|
||||
t.Errorf("deepEqual(%v, %v); unexpected error %q, want %q", test.a, test.b, err.Error(), test.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Recursive struct {
|
||||
x int
|
||||
r *Recursive
|
||||
}
|
||||
|
||||
func TestDeepEqualRecursiveStruct(t *testing.T) {
|
||||
a, b := new(Recursive), new(Recursive)
|
||||
*a = Recursive{12, a}
|
||||
*b = Recursive{12, b}
|
||||
if !deepEqual(a, b) {
|
||||
t.Error("deepEqual(recursive same) = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
type _Complex struct {
|
||||
a int
|
||||
b [3]*_Complex
|
||||
c *string
|
||||
d map[float64]float64
|
||||
}
|
||||
|
||||
func TestDeepEqualComplexStruct(t *testing.T) {
|
||||
m := make(map[float64]float64)
|
||||
stra, strb := "hello", "hello"
|
||||
a, b := new(_Complex), new(_Complex)
|
||||
*a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
|
||||
*b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
|
||||
if !deepEqual(a, b) {
|
||||
t.Error("deepEqual(complex same) = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeepEqualComplexStructInequality(t *testing.T) {
|
||||
m := make(map[float64]float64)
|
||||
stra, strb := "hello", "helloo" // Difference is here
|
||||
a, b := new(_Complex), new(_Complex)
|
||||
*a = _Complex{5, [3]*_Complex{a, b, a}, &stra, m}
|
||||
*b = _Complex{5, [3]*_Complex{b, a, a}, &strb, m}
|
||||
if deepEqual(a, b) {
|
||||
t.Error("deepEqual(complex different) = true, want false")
|
||||
}
|
||||
}
|
||||
|
||||
type UnexpT struct {
|
||||
m map[int]int
|
||||
}
|
||||
|
||||
func TestDeepEqualUnexportedMap(t *testing.T) {
|
||||
// Check that DeepEqual can look at unexported fields.
|
||||
x1 := UnexpT{map[int]int{1: 2}}
|
||||
x2 := UnexpT{map[int]int{1: 2}}
|
||||
if !deepEqual(&x1, &x2) {
|
||||
t.Error("deepEqual(x1, x2) = false, want true")
|
||||
}
|
||||
|
||||
y1 := UnexpT{map[int]int{2: 3}}
|
||||
if deepEqual(&x1, &y1) {
|
||||
t.Error("deepEqual(x1, y1) = true, want false")
|
||||
}
|
||||
}
|
224
vendor/github.com/juju/testing/checkers/file.go
generated
vendored
Normal file
224
vendor/github.com/juju/testing/checkers/file.go
generated
vendored
Normal file
|
@ -0,0 +1,224 @@
|
|||
// Copyright 2013 Canonical Ltd.
|
||||
// Copyright 2014 Cloudbase Solutions SRL
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
// IsNonEmptyFile checker
|
||||
|
||||
type isNonEmptyFileChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var IsNonEmptyFile gc.Checker = &isNonEmptyFileChecker{
|
||||
&gc.CheckerInfo{Name: "IsNonEmptyFile", Params: []string{"obtained"}},
|
||||
}
|
||||
|
||||
func (checker *isNonEmptyFileChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
filename, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
fileInfo, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return false, fmt.Sprintf("%s does not exist", filename)
|
||||
} else if err != nil {
|
||||
return false, fmt.Sprintf("other stat error: %v", err)
|
||||
}
|
||||
if fileInfo.Size() > 0 {
|
||||
return true, ""
|
||||
} else {
|
||||
return false, fmt.Sprintf("%s is empty", filename)
|
||||
}
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(params[0])
|
||||
return false, fmt.Sprintf("obtained value is not a string and has no .String(), %s:%#v", value.Kind(), params[0])
|
||||
}
|
||||
|
||||
// IsDirectory checker
|
||||
|
||||
type isDirectoryChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var IsDirectory gc.Checker = &isDirectoryChecker{
|
||||
&gc.CheckerInfo{Name: "IsDirectory", Params: []string{"obtained"}},
|
||||
}
|
||||
|
||||
func (checker *isDirectoryChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
path, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
fileInfo, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return false, fmt.Sprintf("%s does not exist", path)
|
||||
} else if err != nil {
|
||||
return false, fmt.Sprintf("other stat error: %v", err)
|
||||
}
|
||||
if fileInfo.IsDir() {
|
||||
return true, ""
|
||||
} else {
|
||||
return false, fmt.Sprintf("%s is not a directory", path)
|
||||
}
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(params[0])
|
||||
return false, fmt.Sprintf("obtained value is not a string and has no .String(), %s:%#v", value.Kind(), params[0])
|
||||
}
|
||||
|
||||
// IsSymlink checker
|
||||
|
||||
type isSymlinkChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var IsSymlink gc.Checker = &isSymlinkChecker{
|
||||
&gc.CheckerInfo{Name: "IsSymlink", Params: []string{"obtained"}},
|
||||
}
|
||||
|
||||
func (checker *isSymlinkChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
path, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
fileInfo, err := os.Lstat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return false, fmt.Sprintf("%s does not exist", path)
|
||||
} else if err != nil {
|
||||
return false, fmt.Sprintf("other stat error: %v", err)
|
||||
}
|
||||
if fileInfo.Mode()&os.ModeSymlink != 0 {
|
||||
return true, ""
|
||||
} else {
|
||||
return false, fmt.Sprintf("%s is not a symlink: %+v", path, fileInfo)
|
||||
}
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(params[0])
|
||||
return false, fmt.Sprintf("obtained value is not a string and has no .String(), %s:%#v", value.Kind(), params[0])
|
||||
}
|
||||
|
||||
// DoesNotExist checker makes sure the path specified doesn't exist.
|
||||
|
||||
type doesNotExistChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var DoesNotExist gc.Checker = &doesNotExistChecker{
|
||||
&gc.CheckerInfo{Name: "DoesNotExist", Params: []string{"obtained"}},
|
||||
}
|
||||
|
||||
func (checker *doesNotExistChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
path, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
_, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return true, ""
|
||||
} else if err != nil {
|
||||
return false, fmt.Sprintf("other stat error: %v", err)
|
||||
}
|
||||
return false, fmt.Sprintf("%s exists", path)
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(params[0])
|
||||
return false, fmt.Sprintf("obtained value is not a string and has no .String(), %s:%#v", value.Kind(), params[0])
|
||||
}
|
||||
|
||||
// SymlinkDoesNotExist checker makes sure the path specified doesn't exist.
|
||||
|
||||
type symlinkDoesNotExistChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
var SymlinkDoesNotExist gc.Checker = &symlinkDoesNotExistChecker{
|
||||
&gc.CheckerInfo{Name: "SymlinkDoesNotExist", Params: []string{"obtained"}},
|
||||
}
|
||||
|
||||
func (checker *symlinkDoesNotExistChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
path, isString := stringOrStringer(params[0])
|
||||
if isString {
|
||||
_, err := os.Lstat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return true, ""
|
||||
} else if err != nil {
|
||||
return false, fmt.Sprintf("other stat error: %v", err)
|
||||
}
|
||||
return false, fmt.Sprintf("%s exists", path)
|
||||
}
|
||||
|
||||
value := reflect.ValueOf(params[0])
|
||||
return false, fmt.Sprintf("obtained value is not a string and has no .String(), %s:%#v", value.Kind(), params[0])
|
||||
}
|
||||
|
||||
// Same path checker -- will check that paths are the same OS indepentent
|
||||
|
||||
type samePathChecker struct {
|
||||
*gc.CheckerInfo
|
||||
}
|
||||
|
||||
// SamePath checks paths to see whether they're the same, can follow symlinks and is OS independent
|
||||
var SamePath gc.Checker = &samePathChecker{
|
||||
&gc.CheckerInfo{Name: "SamePath", Params: []string{"obtained", "expected"}},
|
||||
}
|
||||
|
||||
func (checker *samePathChecker) Check(params []interface{}, names []string) (result bool, error string) {
|
||||
// Check for panics
|
||||
defer func() {
|
||||
if panicked := recover(); panicked != nil {
|
||||
result = false
|
||||
error = fmt.Sprint(panicked)
|
||||
}
|
||||
}()
|
||||
|
||||
// Convert input
|
||||
obtained, isStr := stringOrStringer(params[0])
|
||||
if !isStr {
|
||||
return false, fmt.Sprintf("obtained value is not a string and has no .String(), %T:%#v", params[0], params[0])
|
||||
}
|
||||
expected, isStr := stringOrStringer(params[1])
|
||||
if !isStr {
|
||||
return false, fmt.Sprintf("obtained value is not a string and has no .String(), %T:%#v", params[1], params[1])
|
||||
}
|
||||
|
||||
// Convert paths to proper format
|
||||
obtained = filepath.FromSlash(obtained)
|
||||
expected = filepath.FromSlash(expected)
|
||||
|
||||
// If running on Windows, paths will be case-insensitive and thus we
|
||||
// normalize the inputs to a default of all upper-case
|
||||
if runtime.GOOS == "windows" {
|
||||
obtained = strings.ToUpper(obtained)
|
||||
expected = strings.ToUpper(expected)
|
||||
}
|
||||
|
||||
// Same path do not check further
|
||||
if obtained == expected {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// If it's not the same path, check if it points to the same file.
|
||||
// Thus, the cases with windows-shortened paths are accounted for
|
||||
// This will throw an error if it's not a file
|
||||
ob, err := os.Stat(obtained)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
ex, err := os.Stat(expected)
|
||||
if err != nil {
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
res := os.SameFile(ob, ex)
|
||||
if res {
|
||||
return true, ""
|
||||
}
|
||||
return false, fmt.Sprintf("Not the same file")
|
||||
}
|
288
vendor/github.com/juju/testing/checkers/file_test.go
generated
vendored
Normal file
288
vendor/github.com/juju/testing/checkers/file_test.go
generated
vendored
Normal file
|
@ -0,0 +1,288 @@
|
|||
// Copyright 2013 Canonical Ltd.
|
||||
// Copyright 2014 Cloudbase Solutions SRL
|
||||
// Licensed under the LGPLv3, see LICENCE file for details.
|
||||
|
||||
package checkers_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
gc "gopkg.in/check.v1"
|
||||
|
||||
jc "github.com/juju/testing/checkers"
|
||||
)
|
||||
|
||||
type FileSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&FileSuite{})
|
||||
|
||||
func (s *FileSuite) TestIsNonEmptyFile(c *gc.C) {
|
||||
file, err := ioutil.TempFile(c.MkDir(), "")
|
||||
c.Assert(err, gc.IsNil)
|
||||
fmt.Fprintf(file, "something")
|
||||
file.Close()
|
||||
|
||||
c.Assert(file.Name(), jc.IsNonEmptyFile)
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsNonEmptyFileWithEmptyFile(c *gc.C) {
|
||||
file, err := ioutil.TempFile(c.MkDir(), "")
|
||||
c.Assert(err, gc.IsNil)
|
||||
file.Close()
|
||||
|
||||
result, message := jc.IsNonEmptyFile.Check([]interface{}{file.Name()}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, file.Name()+" is empty")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsNonEmptyFileWithMissingFile(c *gc.C) {
|
||||
name := filepath.Join(c.MkDir(), "missing")
|
||||
|
||||
result, message := jc.IsNonEmptyFile.Check([]interface{}{name}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, name+" does not exist")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsNonEmptyFileWithNumber(c *gc.C) {
|
||||
result, message := jc.IsNonEmptyFile.Check([]interface{}{42}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, "obtained value is not a string and has no .String(), int:42")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsDirectory(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
c.Assert(dir, jc.IsDirectory)
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsDirectoryMissing(c *gc.C) {
|
||||
absentDir := filepath.Join(c.MkDir(), "foo")
|
||||
|
||||
result, message := jc.IsDirectory.Check([]interface{}{absentDir}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, absentDir+" does not exist")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsDirectoryWithFile(c *gc.C) {
|
||||
file, err := ioutil.TempFile(c.MkDir(), "")
|
||||
c.Assert(err, gc.IsNil)
|
||||
file.Close()
|
||||
|
||||
result, message := jc.IsDirectory.Check([]interface{}{file.Name()}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, file.Name()+" is not a directory")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsDirectoryWithNumber(c *gc.C) {
|
||||
result, message := jc.IsDirectory.Check([]interface{}{42}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, "obtained value is not a string and has no .String(), int:42")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestDoesNotExist(c *gc.C) {
|
||||
absentDir := filepath.Join(c.MkDir(), "foo")
|
||||
c.Assert(absentDir, jc.DoesNotExist)
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestDoesNotExistWithPath(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
result, message := jc.DoesNotExist.Check([]interface{}{dir}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, dir+" exists")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestDoesNotExistWithSymlink(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
deadPath := filepath.Join(dir, "dead")
|
||||
symlinkPath := filepath.Join(dir, "a-symlink")
|
||||
err := os.Symlink(deadPath, symlinkPath)
|
||||
c.Assert(err, gc.IsNil)
|
||||
// A valid symlink pointing to something that doesn't exist passes.
|
||||
// Use SymlinkDoesNotExist to check for the non-existence of the link itself.
|
||||
c.Assert(symlinkPath, jc.DoesNotExist)
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestDoesNotExistWithNumber(c *gc.C) {
|
||||
result, message := jc.DoesNotExist.Check([]interface{}{42}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, "obtained value is not a string and has no .String(), int:42")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestSymlinkDoesNotExist(c *gc.C) {
|
||||
absentDir := filepath.Join(c.MkDir(), "foo")
|
||||
c.Assert(absentDir, jc.SymlinkDoesNotExist)
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestSymlinkDoesNotExistWithPath(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
result, message := jc.SymlinkDoesNotExist.Check([]interface{}{dir}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, dir+" exists")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestSymlinkDoesNotExistWithSymlink(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
deadPath := filepath.Join(dir, "dead")
|
||||
symlinkPath := filepath.Join(dir, "a-symlink")
|
||||
err := os.Symlink(deadPath, symlinkPath)
|
||||
c.Assert(err, gc.IsNil)
|
||||
|
||||
result, message := jc.SymlinkDoesNotExist.Check([]interface{}{symlinkPath}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, symlinkPath+" exists")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestSymlinkDoesNotExistWithNumber(c *gc.C) {
|
||||
result, message := jc.SymlinkDoesNotExist.Check([]interface{}{42}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, "obtained value is not a string and has no .String(), int:42")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsSymlink(c *gc.C) {
|
||||
file, err := ioutil.TempFile(c.MkDir(), "")
|
||||
c.Assert(err, gc.IsNil)
|
||||
c.Log(file.Name())
|
||||
c.Log(filepath.Dir(file.Name()))
|
||||
symlinkPath := filepath.Join(filepath.Dir(file.Name()), "a-symlink")
|
||||
err = os.Symlink(file.Name(), symlinkPath)
|
||||
c.Assert(err, gc.IsNil)
|
||||
|
||||
c.Assert(symlinkPath, jc.IsSymlink)
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsSymlinkWithFile(c *gc.C) {
|
||||
file, err := ioutil.TempFile(c.MkDir(), "")
|
||||
c.Assert(err, gc.IsNil)
|
||||
result, message := jc.IsSymlink.Check([]interface{}{file.Name()}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, jc.Contains, " is not a symlink")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestIsSymlinkWithDir(c *gc.C) {
|
||||
result, message := jc.IsSymlink.Check([]interface{}{c.MkDir()}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, jc.Contains, " is not a symlink")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestSamePathWithNumber(c *gc.C) {
|
||||
result, message := jc.SamePath.Check([]interface{}{42, 52}, nil)
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, "obtained value is not a string and has no .String(), int:42")
|
||||
}
|
||||
|
||||
func (s *FileSuite) TestSamePathBasic(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
|
||||
result, message := jc.SamePath.Check([]interface{}{dir, dir}, nil)
|
||||
|
||||
c.Assert(result, jc.IsTrue)
|
||||
c.Assert(message, gc.Equals, "")
|
||||
}
|
||||
|
||||
type SamePathLinuxSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&SamePathLinuxSuite{})
|
||||
|
||||
func (s *SamePathLinuxSuite) SetUpSuite(c *gc.C) {
|
||||
if runtime.GOOS == "windows" {
|
||||
c.Skip("Skipped Linux-intented SamePath tests on Windows.")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SamePathLinuxSuite) TestNotSamePathLinuxBasic(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
path1 := filepath.Join(dir, "Test")
|
||||
path2 := filepath.Join(dir, "test")
|
||||
|
||||
result, message := jc.SamePath.Check([]interface{}{path1, path2}, nil)
|
||||
|
||||
c.Assert(result, jc.IsFalse)
|
||||
c.Assert(message, gc.Equals, "stat "+path1+": no such file or directory")
|
||||
}
|
||||
|
||||
func (s *SamePathLinuxSuite) TestSamePathLinuxSymlinks(c *gc.C) {
|
||||
file, err := ioutil.TempFile(c.MkDir(), "")
|
||||
c.Assert(err, gc.IsNil)
|
||||
symlinkPath := filepath.Join(filepath.Dir(file.Name()), "a-symlink")
|
||||
err = os.Symlink(file.Name(), symlinkPath)
|
||||
|
||||
result, message := jc.SamePath.Check([]interface{}{file.Name(), symlinkPath}, nil)
|
||||
|
||||
c.Assert(result, jc.IsTrue)
|
||||
c.Assert(message, gc.Equals, "")
|
||||
}
|
||||
|
||||
type SamePathWindowsSuite struct{}
|
||||
|
||||
var _ = gc.Suite(&SamePathWindowsSuite{})
|
||||
|
||||
func (s *SamePathWindowsSuite) SetUpSuite(c *gc.C) {
|
||||
if runtime.GOOS != "windows" {
|
||||
c.Skip("Skipped Windows-intented SamePath tests.")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SamePathWindowsSuite) TestNotSamePathBasic(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
path1 := filepath.Join(dir, "notTest")
|
||||
path2 := filepath.Join(dir, "test")
|
||||
|
||||
result, message := jc.SamePath.Check([]interface{}{path1, path2}, nil)
|
||||
|
||||
c.Assert(result, jc.IsFalse)
|
||||
path1 = strings.ToUpper(path1)
|
||||
c.Assert(message, gc.Equals, "GetFileAttributesEx "+path1+": The system cannot find the file specified.")
|
||||
}
|
||||
|
||||
func (s *SamePathWindowsSuite) TestSamePathWindowsCaseInsensitive(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
path1 := filepath.Join(dir, "Test")
|
||||
path2 := filepath.Join(dir, "test")
|
||||
|
||||
result, message := jc.SamePath.Check([]interface{}{path1, path2}, nil)
|
||||
|
||||
c.Assert(result, jc.IsTrue)
|
||||
c.Assert(message, gc.Equals, "")
|
||||
}
|
||||
|
||||
func (s *SamePathWindowsSuite) TestSamePathWindowsFixSlashes(c *gc.C) {
|
||||
result, message := jc.SamePath.Check([]interface{}{"C:/Users", "C:\\Users"}, nil)
|
||||
|
||||
c.Assert(result, jc.IsTrue)
|
||||
c.Assert(message, gc.Equals, "")
|
||||
}
|
||||
|
||||
func (s *SamePathWindowsSuite) TestSamePathShortenedPaths(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
dir1, err := ioutil.TempDir(dir, "Programming")
|
||||
defer os.Remove(dir1)
|
||||
c.Assert(err, gc.IsNil)
|
||||
result, message := jc.SamePath.Check([]interface{}{dir + "\\PROGRA~1", dir1}, nil)
|
||||
|
||||
c.Assert(result, jc.IsTrue)
|
||||
c.Assert(message, gc.Equals, "")
|
||||
}
|
||||
|
||||
func (s *SamePathWindowsSuite) TestSamePathShortenedPathsConsistent(c *gc.C) {
|
||||
dir := c.MkDir()
|
||||
dir1, err := ioutil.TempDir(dir, "Programming")
|
||||
defer os.Remove(dir1)
|
||||
c.Assert(err, gc.IsNil)
|
||||
dir2, err := ioutil.TempDir(dir, "Program Files")
|
||||
defer os.Remove(dir2)
|
||||
c.Assert(err, gc.IsNil)
|
||||
|
||||
result, message := jc.SamePath.Check([]interface{}{dir + "\\PROGRA~1", dir2}, nil)
|
||||
|
||||
c.Assert(result, gc.Not(jc.IsTrue))
|
||||
c.Assert(message, gc.Equals, "Not the same file")
|
||||
|
||||
result, message = jc.SamePath.Check([]interface{}{"C:/PROGRA~2", "C:/Program Files (x86)"}, nil)
|
||||
|
||||
c.Assert(result, jc.IsTrue)
|
||||
c.Assert(message, gc.Equals, "")
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue