chore: remove vendor
This commit is contained in:
parent
e03659cc70
commit
92fd3a5da7
21
vendor/github.com/appleboy/drone-facebook/LICENSE
generated
vendored
21
vendor/github.com/appleboy/drone-facebook/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2016 Bo-Yi Wu
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
134
vendor/github.com/appleboy/drone-facebook/template/template.go
generated
vendored
134
vendor/github.com/appleboy/drone-facebook/template/template.go
generated
vendored
@ -1,134 +0,0 @@
|
|||||||
package template
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"github.com/aymerick/raymond"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
raymond.RegisterHelpers(funcs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render parses and executes a template, returning the results in string format.
|
|
||||||
func Render(template string, payload interface{}) (s string, err error) {
|
|
||||||
u, err := url.Parse(template)
|
|
||||||
if err == nil {
|
|
||||||
switch u.Scheme {
|
|
||||||
case "http", "https":
|
|
||||||
res, err := http.Get(template)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
out, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
template = string(out)
|
|
||||||
|
|
||||||
case "file":
|
|
||||||
out, err := ioutil.ReadFile(u.Path)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
template = string(out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return raymond.Render(template, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RenderTrim parses and executes a template, returning the results in string
|
|
||||||
// format. The result is trimmed to remove left and right padding and newlines
|
|
||||||
// that may be added unintentially in the template markup.
|
|
||||||
func RenderTrim(template string, playload interface{}) (string, error) {
|
|
||||||
out, err := Render(template, playload)
|
|
||||||
return strings.Trim(out, " \n"), err
|
|
||||||
}
|
|
||||||
|
|
||||||
var funcs = map[string]interface{}{
|
|
||||||
"uppercasefirst": uppercaseFirst,
|
|
||||||
"uppercase": strings.ToUpper,
|
|
||||||
"lowercase": strings.ToLower,
|
|
||||||
"duration": toDuration,
|
|
||||||
"datetime": toDatetime,
|
|
||||||
"success": isSuccess,
|
|
||||||
"failure": isFailure,
|
|
||||||
"truncate": truncate,
|
|
||||||
"urlencode": urlencode,
|
|
||||||
"buildtime": buildTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
func truncate(s string, len int) string {
|
|
||||||
if utf8.RuneCountInString(s) <= len {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
runes := []rune(s)
|
|
||||||
return string(runes[:len])
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func uppercaseFirst(s string) string {
|
|
||||||
a := []rune(s)
|
|
||||||
a[0] = unicode.ToUpper(a[0])
|
|
||||||
s = string(a)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func toDuration(started, finished float64) string {
|
|
||||||
return fmt.Sprint(time.Duration(finished-started) * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
func buildTime(started float64) string {
|
|
||||||
finished := float64(time.Now().Unix())
|
|
||||||
return fmt.Sprint(time.Duration(finished-started) * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
func toDatetime(timestamp float64, layout, zone string) string {
|
|
||||||
if len(zone) == 0 {
|
|
||||||
return time.Unix(int64(timestamp), 0).Format(layout)
|
|
||||||
}
|
|
||||||
loc, err := time.LoadLocation(zone)
|
|
||||||
if err != nil {
|
|
||||||
return time.Unix(int64(timestamp), 0).Local().Format(layout)
|
|
||||||
}
|
|
||||||
return time.Unix(int64(timestamp), 0).In(loc).Format(layout)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isSuccess(conditional bool, options *raymond.Options) string {
|
|
||||||
if !conditional {
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch options.ParamStr(0) {
|
|
||||||
case "success":
|
|
||||||
return options.Fn()
|
|
||||||
default:
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isFailure(conditional bool, options *raymond.Options) string {
|
|
||||||
if !conditional {
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
switch options.ParamStr(0) {
|
|
||||||
case "failure", "error", "killed":
|
|
||||||
return options.Fn()
|
|
||||||
default:
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func urlencode(options *raymond.Options) string {
|
|
||||||
return url.QueryEscape(options.Fn())
|
|
||||||
}
|
|
46
vendor/github.com/aymerick/raymond/BENCHMARKS.md
generated
vendored
46
vendor/github.com/aymerick/raymond/BENCHMARKS.md
generated
vendored
@ -1,46 +0,0 @@
|
|||||||
# Benchmarks
|
|
||||||
|
|
||||||
Hardware: MacBookPro11,1 - Intel Core i5 - 2,6 GHz - 8 Go RAM
|
|
||||||
|
|
||||||
With:
|
|
||||||
|
|
||||||
- handlebars.js #8cba84df119c317fcebc49fb285518542ca9c2d0
|
|
||||||
- raymond #7bbaaf50ed03c96b56687d7fa6c6e04e02375a98
|
|
||||||
|
|
||||||
|
|
||||||
## handlebars.js (ops/ms)
|
|
||||||
|
|
||||||
arguments 198 ±4 (5)
|
|
||||||
array-each 568 ±23 (5)
|
|
||||||
array-mustache 522 ±18 (4)
|
|
||||||
complex 71 ±7 (3)
|
|
||||||
data 67 ±2 (3)
|
|
||||||
depth-1 47 ±2 (3)
|
|
||||||
depth-2 14 ±1 (2)
|
|
||||||
object-mustache 1099 ±47 (5)
|
|
||||||
object 907 ±58 (4)
|
|
||||||
partial-recursion 46 ±3 (4)
|
|
||||||
partial 68 ±3 (3)
|
|
||||||
paths 1650 ±50 (3)
|
|
||||||
string 2552 ±157 (3)
|
|
||||||
subexpression 141 ±2 (4)
|
|
||||||
variables 2671 ±83 (4)
|
|
||||||
|
|
||||||
|
|
||||||
## raymond
|
|
||||||
|
|
||||||
BenchmarkArguments 200000 6642 ns/op 151 ops/ms
|
|
||||||
BenchmarkArrayEach 100000 19584 ns/op 51 ops/ms
|
|
||||||
BenchmarkArrayMustache 100000 17305 ns/op 58 ops/ms
|
|
||||||
BenchmarkComplex 30000 50270 ns/op 20 ops/ms
|
|
||||||
BenchmarkData 50000 25551 ns/op 39 ops/ms
|
|
||||||
BenchmarkDepth1 100000 20162 ns/op 50 ops/ms
|
|
||||||
BenchmarkDepth2 30000 47782 ns/op 21 ops/ms
|
|
||||||
BenchmarkObjectMustache 200000 7668 ns/op 130 ops/ms
|
|
||||||
BenchmarkObject 200000 8843 ns/op 113 ops/ms
|
|
||||||
BenchmarkPartialRecursion 50000 23139 ns/op 43 ops/ms
|
|
||||||
BenchmarkPartial 50000 31015 ns/op 32 ops/ms
|
|
||||||
BenchmarkPath 200000 8997 ns/op 111 ops/ms
|
|
||||||
BenchmarkString 1000000 1879 ns/op 532 ops/ms
|
|
||||||
BenchmarkSubExpression 300000 4935 ns/op 203 ops/ms
|
|
||||||
BenchmarkVariables 200000 6478 ns/op 154 ops/ms
|
|
33
vendor/github.com/aymerick/raymond/CHANGELOG.md
generated
vendored
33
vendor/github.com/aymerick/raymond/CHANGELOG.md
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
# Raymond Changelog
|
|
||||||
|
|
||||||
### Raymond 2.0.1 _(June 01, 2016)_
|
|
||||||
|
|
||||||
- [BUGFIX] Removes data races [#3](https://github.com/aymerick/raymond/issues/3) - Thanks [@markbates](https://github.com/markbates)
|
|
||||||
|
|
||||||
### Raymond 2.0.0 _(May 01, 2016)_
|
|
||||||
|
|
||||||
- [BUGFIX] Fixes passing of context in helper options [#2](https://github.com/aymerick/raymond/issues/2) - Thanks [@GhostRussia](https://github.com/GhostRussia)
|
|
||||||
- [BREAKING] Renames and unexports constants:
|
|
||||||
|
|
||||||
- `handlebars.DUMP_TPL`
|
|
||||||
- `lexer.ESCAPED_ESCAPED_OPEN_MUSTACHE`
|
|
||||||
- `lexer.ESCAPED_OPEN_MUSTACHE`
|
|
||||||
- `lexer.OPEN_MUSTACHE`
|
|
||||||
- `lexer.CLOSE_MUSTACHE`
|
|
||||||
- `lexer.CLOSE_STRIP_MUSTACHE`
|
|
||||||
- `lexer.CLOSE_UNESCAPED_STRIP_MUSTACHE`
|
|
||||||
- `lexer.DUMP_TOKEN_POS`
|
|
||||||
- `lexer.DUMP_ALL_TOKENS_VAL`
|
|
||||||
|
|
||||||
|
|
||||||
### Raymond 1.1.0 _(June 15, 2015)_
|
|
||||||
|
|
||||||
- Permits templates references with lowercase versions of struct fields.
|
|
||||||
- Adds `ParseFile()` function.
|
|
||||||
- Adds `RegisterPartialFile()`, `RegisterPartialFiles()` and `Clone()` methods on `Template`.
|
|
||||||
- Helpers can now be struct methods.
|
|
||||||
- Ensures safe concurrent access to helpers and partials.
|
|
||||||
|
|
||||||
### Raymond 1.0.0 _(June 09, 2015)_
|
|
||||||
|
|
||||||
- This is the first release. Raymond supports almost all handlebars features. See https://github.com/aymerick/raymond#limitations for a list of differences with the javascript implementation.
|
|
22
vendor/github.com/aymerick/raymond/LICENSE
generated
vendored
22
vendor/github.com/aymerick/raymond/LICENSE
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Aymerick JEHANNE
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
1417
vendor/github.com/aymerick/raymond/README.md
generated
vendored
1417
vendor/github.com/aymerick/raymond/README.md
generated
vendored
File diff suppressed because it is too large
Load Diff
1
vendor/github.com/aymerick/raymond/VERSION
generated
vendored
1
vendor/github.com/aymerick/raymond/VERSION
generated
vendored
@ -1 +0,0 @@
|
|||||||
2.0.1
|
|
785
vendor/github.com/aymerick/raymond/ast/node.go
generated
vendored
785
vendor/github.com/aymerick/raymond/ast/node.go
generated
vendored
@ -1,785 +0,0 @@
|
|||||||
// Package ast provides structures to represent a handlebars Abstract Syntax Tree, and a Visitor interface to visit that tree.
|
|
||||||
package ast
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// References:
|
|
||||||
// - https://github.com/wycats/handlebars.js/blob/master/lib/handlebars/compiler/ast.js
|
|
||||||
// - https://github.com/wycats/handlebars.js/blob/master/docs/compiler-api.md
|
|
||||||
// - https://github.com/golang/go/blob/master/src/text/template/parse/node.go
|
|
||||||
|
|
||||||
// Node is an element in the AST.
|
|
||||||
type Node interface {
|
|
||||||
// node type
|
|
||||||
Type() NodeType
|
|
||||||
|
|
||||||
// location of node in original input string
|
|
||||||
Location() Loc
|
|
||||||
|
|
||||||
// string representation, used for debugging
|
|
||||||
String() string
|
|
||||||
|
|
||||||
// accepts visitor
|
|
||||||
Accept(Visitor) interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visitor is the interface to visit an AST.
|
|
||||||
type Visitor interface {
|
|
||||||
VisitProgram(*Program) interface{}
|
|
||||||
|
|
||||||
// statements
|
|
||||||
VisitMustache(*MustacheStatement) interface{}
|
|
||||||
VisitBlock(*BlockStatement) interface{}
|
|
||||||
VisitPartial(*PartialStatement) interface{}
|
|
||||||
VisitContent(*ContentStatement) interface{}
|
|
||||||
VisitComment(*CommentStatement) interface{}
|
|
||||||
|
|
||||||
// expressions
|
|
||||||
VisitExpression(*Expression) interface{}
|
|
||||||
VisitSubExpression(*SubExpression) interface{}
|
|
||||||
VisitPath(*PathExpression) interface{}
|
|
||||||
|
|
||||||
// literals
|
|
||||||
VisitString(*StringLiteral) interface{}
|
|
||||||
VisitBoolean(*BooleanLiteral) interface{}
|
|
||||||
VisitNumber(*NumberLiteral) interface{}
|
|
||||||
|
|
||||||
// miscellaneous
|
|
||||||
VisitHash(*Hash) interface{}
|
|
||||||
VisitHashPair(*HashPair) interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeType represents an AST Node type.
|
|
||||||
type NodeType int
|
|
||||||
|
|
||||||
// Type returns itself, and permits struct includers to satisfy that part of Node interface.
|
|
||||||
func (t NodeType) Type() NodeType {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// NodeProgram is the program node
|
|
||||||
NodeProgram NodeType = iota
|
|
||||||
|
|
||||||
// NodeMustache is the mustache statement node
|
|
||||||
NodeMustache
|
|
||||||
|
|
||||||
// NodeBlock is the block statement node
|
|
||||||
NodeBlock
|
|
||||||
|
|
||||||
// NodePartial is the partial statement node
|
|
||||||
NodePartial
|
|
||||||
|
|
||||||
// NodeContent is the content statement node
|
|
||||||
NodeContent
|
|
||||||
|
|
||||||
// NodeComment is the comment statement node
|
|
||||||
NodeComment
|
|
||||||
|
|
||||||
// NodeExpression is the expression node
|
|
||||||
NodeExpression
|
|
||||||
|
|
||||||
// NodeSubExpression is the subexpression node
|
|
||||||
NodeSubExpression
|
|
||||||
|
|
||||||
// NodePath is the expression path node
|
|
||||||
NodePath
|
|
||||||
|
|
||||||
// NodeBoolean is the literal boolean node
|
|
||||||
NodeBoolean
|
|
||||||
|
|
||||||
// NodeNumber is the literal number node
|
|
||||||
NodeNumber
|
|
||||||
|
|
||||||
// NodeString is the literal string node
|
|
||||||
NodeString
|
|
||||||
|
|
||||||
// NodeHash is the hash node
|
|
||||||
NodeHash
|
|
||||||
|
|
||||||
// NodeHashPair is the hash pair node
|
|
||||||
NodeHashPair
|
|
||||||
)
|
|
||||||
|
|
||||||
// Loc represents the position of a parsed node in source file.
|
|
||||||
type Loc struct {
|
|
||||||
Pos int // Byte position
|
|
||||||
Line int // Line number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Location returns itself, and permits struct includers to satisfy that part of Node interface.
|
|
||||||
func (l Loc) Location() Loc {
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip describes node whitespace management.
|
|
||||||
type Strip struct {
|
|
||||||
Open bool
|
|
||||||
Close bool
|
|
||||||
|
|
||||||
OpenStandalone bool
|
|
||||||
CloseStandalone bool
|
|
||||||
InlineStandalone bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStrip instanciates a Strip for given open and close mustaches.
|
|
||||||
func NewStrip(openStr, closeStr string) *Strip {
|
|
||||||
return &Strip{
|
|
||||||
Open: (len(openStr) > 2) && openStr[2] == '~',
|
|
||||||
Close: (len(closeStr) > 2) && closeStr[len(closeStr)-3] == '~',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStripForStr instanciates a Strip for given tag.
|
|
||||||
func NewStripForStr(str string) *Strip {
|
|
||||||
return &Strip{
|
|
||||||
Open: (len(str) > 2) && str[2] == '~',
|
|
||||||
Close: (len(str) > 2) && str[len(str)-3] == '~',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (s *Strip) String() string {
|
|
||||||
return fmt.Sprintf("Open: %t, Close: %t, OpenStandalone: %t, CloseStandalone: %t, InlineStandalone: %t", s.Open, s.Close, s.OpenStandalone, s.CloseStandalone, s.InlineStandalone)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Program
|
|
||||||
//
|
|
||||||
|
|
||||||
// Program represents a program node.
|
|
||||||
type Program struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Body []Node // [ Statement ... ]
|
|
||||||
BlockParams []string
|
|
||||||
Chained bool
|
|
||||||
|
|
||||||
// whitespace management
|
|
||||||
Strip *Strip
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProgram instanciates a new program node.
|
|
||||||
func NewProgram(pos int, line int) *Program {
|
|
||||||
return &Program{
|
|
||||||
NodeType: NodeProgram,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *Program) String() string {
|
|
||||||
return fmt.Sprintf("Program{Pos: %d}", node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *Program) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitProgram(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddStatement adds given statement to program.
|
|
||||||
func (node *Program) AddStatement(statement Node) {
|
|
||||||
node.Body = append(node.Body, statement)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Mustache Statement
|
|
||||||
//
|
|
||||||
|
|
||||||
// MustacheStatement represents a mustache node.
|
|
||||||
type MustacheStatement struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Unescaped bool
|
|
||||||
Expression *Expression
|
|
||||||
|
|
||||||
// whitespace management
|
|
||||||
Strip *Strip
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMustacheStatement instanciates a new mustache node.
|
|
||||||
func NewMustacheStatement(pos int, line int, unescaped bool) *MustacheStatement {
|
|
||||||
return &MustacheStatement{
|
|
||||||
NodeType: NodeMustache,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
Unescaped: unescaped,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *MustacheStatement) String() string {
|
|
||||||
return fmt.Sprintf("Mustache{Pos: %d}", node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *MustacheStatement) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitMustache(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Block Statement
|
|
||||||
//
|
|
||||||
|
|
||||||
// BlockStatement represents a block node.
|
|
||||||
type BlockStatement struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Expression *Expression
|
|
||||||
|
|
||||||
Program *Program
|
|
||||||
Inverse *Program
|
|
||||||
|
|
||||||
// whitespace management
|
|
||||||
OpenStrip *Strip
|
|
||||||
InverseStrip *Strip
|
|
||||||
CloseStrip *Strip
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBlockStatement instanciates a new block node.
|
|
||||||
func NewBlockStatement(pos int, line int) *BlockStatement {
|
|
||||||
return &BlockStatement{
|
|
||||||
NodeType: NodeBlock,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *BlockStatement) String() string {
|
|
||||||
return fmt.Sprintf("Block{Pos: %d}", node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *BlockStatement) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitBlock(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Partial Statement
|
|
||||||
//
|
|
||||||
|
|
||||||
// PartialStatement represents a partial node.
|
|
||||||
type PartialStatement struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Name Node // PathExpression | SubExpression
|
|
||||||
Params []Node // [ Expression ... ]
|
|
||||||
Hash *Hash
|
|
||||||
|
|
||||||
// whitespace management
|
|
||||||
Strip *Strip
|
|
||||||
Indent string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPartialStatement instanciates a new partial node.
|
|
||||||
func NewPartialStatement(pos int, line int) *PartialStatement {
|
|
||||||
return &PartialStatement{
|
|
||||||
NodeType: NodePartial,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *PartialStatement) String() string {
|
|
||||||
return fmt.Sprintf("Partial{Name:%s, Pos:%d}", node.Name, node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *PartialStatement) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitPartial(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Content Statement
|
|
||||||
//
|
|
||||||
|
|
||||||
// ContentStatement represents a content node.
|
|
||||||
type ContentStatement struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Value string
|
|
||||||
Original string
|
|
||||||
|
|
||||||
// whitespace management
|
|
||||||
RightStripped bool
|
|
||||||
LeftStripped bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContentStatement instanciates a new content node.
|
|
||||||
func NewContentStatement(pos int, line int, val string) *ContentStatement {
|
|
||||||
return &ContentStatement{
|
|
||||||
NodeType: NodeContent,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
|
|
||||||
Value: val,
|
|
||||||
Original: val,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *ContentStatement) String() string {
|
|
||||||
return fmt.Sprintf("Content{Value:'%s', Pos:%d}", node.Value, node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *ContentStatement) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitContent(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Comment Statement
|
|
||||||
//
|
|
||||||
|
|
||||||
// CommentStatement represents a comment node.
|
|
||||||
type CommentStatement struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Value string
|
|
||||||
|
|
||||||
// whitespace management
|
|
||||||
Strip *Strip
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCommentStatement instanciates a new comment node.
|
|
||||||
func NewCommentStatement(pos int, line int, val string) *CommentStatement {
|
|
||||||
return &CommentStatement{
|
|
||||||
NodeType: NodeComment,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
|
|
||||||
Value: val,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *CommentStatement) String() string {
|
|
||||||
return fmt.Sprintf("Comment{Value:'%s', Pos:%d}", node.Value, node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *CommentStatement) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitComment(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Expression
|
|
||||||
//
|
|
||||||
|
|
||||||
// Expression represents an expression node.
|
|
||||||
type Expression struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Path Node // PathExpression | StringLiteral | BooleanLiteral | NumberLiteral
|
|
||||||
Params []Node // [ Expression ... ]
|
|
||||||
Hash *Hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewExpression instanciates a new expression node.
|
|
||||||
func NewExpression(pos int, line int) *Expression {
|
|
||||||
return &Expression{
|
|
||||||
NodeType: NodeExpression,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *Expression) String() string {
|
|
||||||
return fmt.Sprintf("Expr{Path:%s, Pos:%d}", node.Path, node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *Expression) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitExpression(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HelperName returns helper name, or an empty string if this expression can't be a helper.
|
|
||||||
func (node *Expression) HelperName() string {
|
|
||||||
path, ok := node.Path.(*PathExpression)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if path.Data || (len(path.Parts) != 1) || (path.Depth > 0) || path.Scoped {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return path.Parts[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// FieldPath returns path expression representing a field path, or nil if this is not a field path.
|
|
||||||
func (node *Expression) FieldPath() *PathExpression {
|
|
||||||
path, ok := node.Path.(*PathExpression)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
// LiteralStr returns the string representation of literal value, with a boolean set to false if this is not a literal.
|
|
||||||
func (node *Expression) LiteralStr() (string, bool) {
|
|
||||||
return LiteralStr(node.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonical returns the canonical form of expression node as a string.
|
|
||||||
func (node *Expression) Canonical() string {
|
|
||||||
if str, ok := HelperNameStr(node.Path); ok {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// HelperNameStr returns the string representation of a helper name, with a boolean set to false if this is not a valid helper name.
|
|
||||||
//
|
|
||||||
// helperName : path | dataName | STRING | NUMBER | BOOLEAN | UNDEFINED | NULL
|
|
||||||
func HelperNameStr(node Node) (string, bool) {
|
|
||||||
// PathExpression
|
|
||||||
if str, ok := PathExpressionStr(node); ok {
|
|
||||||
return str, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Literal
|
|
||||||
if str, ok := LiteralStr(node); ok {
|
|
||||||
return str, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
// PathExpressionStr returns the string representation of path expression value, with a boolean set to false if this is not a path expression.
|
|
||||||
func PathExpressionStr(node Node) (string, bool) {
|
|
||||||
if path, ok := node.(*PathExpression); ok {
|
|
||||||
result := path.Original
|
|
||||||
|
|
||||||
// "[foo bar]"" => "foo bar"
|
|
||||||
if (len(result) >= 2) && (result[0] == '[') && (result[len(result)-1] == ']') {
|
|
||||||
result = result[1 : len(result)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
// LiteralStr returns the string representation of literal value, with a boolean set to false if this is not a literal.
|
|
||||||
func LiteralStr(node Node) (string, bool) {
|
|
||||||
if lit, ok := node.(*StringLiteral); ok {
|
|
||||||
return lit.Value, true
|
|
||||||
}
|
|
||||||
|
|
||||||
if lit, ok := node.(*BooleanLiteral); ok {
|
|
||||||
return lit.Canonical(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
if lit, ok := node.(*NumberLiteral); ok {
|
|
||||||
return lit.Canonical(), true
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// SubExpression
|
|
||||||
//
|
|
||||||
|
|
||||||
// SubExpression represents a subexpression node.
|
|
||||||
type SubExpression struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Expression *Expression
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewSubExpression instanciates a new subexpression node.
|
|
||||||
func NewSubExpression(pos int, line int) *SubExpression {
|
|
||||||
return &SubExpression{
|
|
||||||
NodeType: NodeSubExpression,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *SubExpression) String() string {
|
|
||||||
return fmt.Sprintf("Sexp{Path:%s, Pos:%d}", node.Expression.Path, node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *SubExpression) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitSubExpression(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Path Expression
|
|
||||||
//
|
|
||||||
|
|
||||||
// PathExpression represents a path expression node.
|
|
||||||
type PathExpression struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Original string
|
|
||||||
Depth int
|
|
||||||
Parts []string
|
|
||||||
Data bool
|
|
||||||
Scoped bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPathExpression instanciates a new path expression node.
|
|
||||||
func NewPathExpression(pos int, line int, data bool) *PathExpression {
|
|
||||||
result := &PathExpression{
|
|
||||||
NodeType: NodePath,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
|
|
||||||
if data {
|
|
||||||
result.Original = "@"
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *PathExpression) String() string {
|
|
||||||
return fmt.Sprintf("Path{Original:'%s', Pos:%d}", node.Original, node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *PathExpression) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitPath(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Part adds path part.
|
|
||||||
func (node *PathExpression) Part(part string) {
|
|
||||||
node.Original += part
|
|
||||||
|
|
||||||
switch part {
|
|
||||||
case "..":
|
|
||||||
node.Depth++
|
|
||||||
node.Scoped = true
|
|
||||||
case ".", "this":
|
|
||||||
node.Scoped = true
|
|
||||||
default:
|
|
||||||
node.Parts = append(node.Parts, part)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sep adds path separator.
|
|
||||||
func (node *PathExpression) Sep(separator string) {
|
|
||||||
node.Original += separator
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsDataRoot returns true if path expression is @root.
|
|
||||||
func (node *PathExpression) IsDataRoot() bool {
|
|
||||||
return node.Data && (node.Parts[0] == "root")
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// String Literal
|
|
||||||
//
|
|
||||||
|
|
||||||
// StringLiteral represents a string node.
|
|
||||||
type StringLiteral struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStringLiteral instanciates a new string node.
|
|
||||||
func NewStringLiteral(pos int, line int, val string) *StringLiteral {
|
|
||||||
return &StringLiteral{
|
|
||||||
NodeType: NodeString,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
|
|
||||||
Value: val,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *StringLiteral) String() string {
|
|
||||||
return fmt.Sprintf("String{Value:'%s', Pos:%d}", node.Value, node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *StringLiteral) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitString(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Boolean Literal
|
|
||||||
//
|
|
||||||
|
|
||||||
// BooleanLiteral represents a boolean node.
|
|
||||||
type BooleanLiteral struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Value bool
|
|
||||||
Original string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBooleanLiteral instanciates a new boolean node.
|
|
||||||
func NewBooleanLiteral(pos int, line int, val bool, original string) *BooleanLiteral {
|
|
||||||
return &BooleanLiteral{
|
|
||||||
NodeType: NodeBoolean,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
|
|
||||||
Value: val,
|
|
||||||
Original: original,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *BooleanLiteral) String() string {
|
|
||||||
return fmt.Sprintf("Boolean{Value:%s, Pos:%d}", node.Canonical(), node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *BooleanLiteral) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitBoolean(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonical returns the canonical form of boolean node as a string (ie. "true" | "false").
|
|
||||||
func (node *BooleanLiteral) Canonical() string {
|
|
||||||
if node.Value {
|
|
||||||
return "true"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "false"
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Number Literal
|
|
||||||
//
|
|
||||||
|
|
||||||
// NumberLiteral represents a number node.
|
|
||||||
type NumberLiteral struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Value float64
|
|
||||||
IsInt bool
|
|
||||||
Original string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewNumberLiteral instanciates a new number node.
|
|
||||||
func NewNumberLiteral(pos int, line int, val float64, isInt bool, original string) *NumberLiteral {
|
|
||||||
return &NumberLiteral{
|
|
||||||
NodeType: NodeNumber,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
|
|
||||||
Value: val,
|
|
||||||
IsInt: isInt,
|
|
||||||
Original: original,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *NumberLiteral) String() string {
|
|
||||||
return fmt.Sprintf("Number{Value:%s, Pos:%d}", node.Canonical(), node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *NumberLiteral) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitNumber(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonical returns the canonical form of number node as a string (eg: "12", "-1.51").
|
|
||||||
func (node *NumberLiteral) Canonical() string {
|
|
||||||
prec := -1
|
|
||||||
if node.IsInt {
|
|
||||||
prec = 0
|
|
||||||
}
|
|
||||||
return strconv.FormatFloat(node.Value, 'f', prec, 64)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Number returns an integer or a float.
|
|
||||||
func (node *NumberLiteral) Number() interface{} {
|
|
||||||
if node.IsInt {
|
|
||||||
return int(node.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return node.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Hash
|
|
||||||
//
|
|
||||||
|
|
||||||
// Hash represents a hash node.
|
|
||||||
type Hash struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Pairs []*HashPair
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHash instanciates a new hash node.
|
|
||||||
func NewHash(pos int, line int) *Hash {
|
|
||||||
return &Hash{
|
|
||||||
NodeType: NodeHash,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *Hash) String() string {
|
|
||||||
result := fmt.Sprintf("Hash{[%d", node.Loc.Pos)
|
|
||||||
|
|
||||||
for i, p := range node.Pairs {
|
|
||||||
if i > 0 {
|
|
||||||
result += ", "
|
|
||||||
}
|
|
||||||
result += p.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return result + fmt.Sprintf("], Pos:%d}", node.Loc.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *Hash) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitHash(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// HashPair
|
|
||||||
//
|
|
||||||
|
|
||||||
// HashPair represents a hash pair node.
|
|
||||||
type HashPair struct {
|
|
||||||
NodeType
|
|
||||||
Loc
|
|
||||||
|
|
||||||
Key string
|
|
||||||
Val Node // Expression
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHashPair instanciates a new hash pair node.
|
|
||||||
func NewHashPair(pos int, line int) *HashPair {
|
|
||||||
return &HashPair{
|
|
||||||
NodeType: NodeHashPair,
|
|
||||||
Loc: Loc{pos, line},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a string representation of receiver that can be used for debugging.
|
|
||||||
func (node *HashPair) String() string {
|
|
||||||
return node.Key + "=" + node.Val.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accept is the receiver entry point for visitors.
|
|
||||||
func (node *HashPair) Accept(visitor Visitor) interface{} {
|
|
||||||
return visitor.VisitHashPair(node)
|
|
||||||
}
|
|
279
vendor/github.com/aymerick/raymond/ast/print.go
generated
vendored
279
vendor/github.com/aymerick/raymond/ast/print.go
generated
vendored
@ -1,279 +0,0 @@
|
|||||||
package ast
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// printVisitor implements the Visitor interface to print a AST.
|
|
||||||
type printVisitor struct {
|
|
||||||
buf string
|
|
||||||
depth int
|
|
||||||
|
|
||||||
original bool
|
|
||||||
inBlock bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func newPrintVisitor() *printVisitor {
|
|
||||||
return &printVisitor{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print returns a string representation of given AST, that can be used for debugging purpose.
|
|
||||||
func Print(node Node) string {
|
|
||||||
visitor := newPrintVisitor()
|
|
||||||
node.Accept(visitor)
|
|
||||||
return visitor.output()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *printVisitor) output() string {
|
|
||||||
return v.buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *printVisitor) indent() {
|
|
||||||
for i := 0; i < v.depth; {
|
|
||||||
v.buf += " "
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *printVisitor) str(val string) {
|
|
||||||
v.buf += val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *printVisitor) nl() {
|
|
||||||
v.str("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *printVisitor) line(val string) {
|
|
||||||
v.indent()
|
|
||||||
v.str(val)
|
|
||||||
v.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Visitor interface
|
|
||||||
//
|
|
||||||
|
|
||||||
// Statements
|
|
||||||
|
|
||||||
// VisitProgram implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitProgram(node *Program) interface{} {
|
|
||||||
if len(node.BlockParams) > 0 {
|
|
||||||
v.line("BLOCK PARAMS: [ " + strings.Join(node.BlockParams, " ") + " ]")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, n := range node.Body {
|
|
||||||
n.Accept(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitMustache implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitMustache(node *MustacheStatement) interface{} {
|
|
||||||
v.indent()
|
|
||||||
v.str("{{ ")
|
|
||||||
|
|
||||||
node.Expression.Accept(v)
|
|
||||||
|
|
||||||
v.str(" }}")
|
|
||||||
v.nl()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitBlock implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitBlock(node *BlockStatement) interface{} {
|
|
||||||
v.inBlock = true
|
|
||||||
|
|
||||||
v.line("BLOCK:")
|
|
||||||
v.depth++
|
|
||||||
|
|
||||||
node.Expression.Accept(v)
|
|
||||||
|
|
||||||
if node.Program != nil {
|
|
||||||
v.line("PROGRAM:")
|
|
||||||
v.depth++
|
|
||||||
node.Program.Accept(v)
|
|
||||||
v.depth--
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.Inverse != nil {
|
|
||||||
// if node.Program != nil {
|
|
||||||
// v.depth++
|
|
||||||
// }
|
|
||||||
|
|
||||||
v.line("{{^}}")
|
|
||||||
v.depth++
|
|
||||||
node.Inverse.Accept(v)
|
|
||||||
v.depth--
|
|
||||||
|
|
||||||
// if node.Program != nil {
|
|
||||||
// v.depth--
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
v.inBlock = false
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitPartial implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitPartial(node *PartialStatement) interface{} {
|
|
||||||
v.indent()
|
|
||||||
v.str("{{> PARTIAL:")
|
|
||||||
|
|
||||||
v.original = true
|
|
||||||
node.Name.Accept(v)
|
|
||||||
v.original = false
|
|
||||||
|
|
||||||
if len(node.Params) > 0 {
|
|
||||||
v.str(" ")
|
|
||||||
node.Params[0].Accept(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// hash
|
|
||||||
if node.Hash != nil {
|
|
||||||
v.str(" ")
|
|
||||||
node.Hash.Accept(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
v.str(" }}")
|
|
||||||
v.nl()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitContent implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitContent(node *ContentStatement) interface{} {
|
|
||||||
v.line("CONTENT[ '" + node.Value + "' ]")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitComment implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitComment(node *CommentStatement) interface{} {
|
|
||||||
v.line("{{! '" + node.Value + "' }}")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expressions
|
|
||||||
|
|
||||||
// VisitExpression implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitExpression(node *Expression) interface{} {
|
|
||||||
if v.inBlock {
|
|
||||||
v.indent()
|
|
||||||
}
|
|
||||||
|
|
||||||
// path
|
|
||||||
node.Path.Accept(v)
|
|
||||||
|
|
||||||
// params
|
|
||||||
v.str(" [")
|
|
||||||
for i, n := range node.Params {
|
|
||||||
if i > 0 {
|
|
||||||
v.str(", ")
|
|
||||||
}
|
|
||||||
n.Accept(v)
|
|
||||||
}
|
|
||||||
v.str("]")
|
|
||||||
|
|
||||||
// hash
|
|
||||||
if node.Hash != nil {
|
|
||||||
v.str(" ")
|
|
||||||
node.Hash.Accept(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.inBlock {
|
|
||||||
v.nl()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitSubExpression implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitSubExpression(node *SubExpression) interface{} {
|
|
||||||
node.Expression.Accept(v)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitPath implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitPath(node *PathExpression) interface{} {
|
|
||||||
if v.original {
|
|
||||||
v.str(node.Original)
|
|
||||||
} else {
|
|
||||||
path := strings.Join(node.Parts, "/")
|
|
||||||
|
|
||||||
result := ""
|
|
||||||
if node.Data {
|
|
||||||
result += "@"
|
|
||||||
}
|
|
||||||
|
|
||||||
v.str(result + "PATH:" + path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Literals
|
|
||||||
|
|
||||||
// VisitString implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitString(node *StringLiteral) interface{} {
|
|
||||||
if v.original {
|
|
||||||
v.str(node.Value)
|
|
||||||
} else {
|
|
||||||
v.str("\"" + node.Value + "\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitBoolean implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitBoolean(node *BooleanLiteral) interface{} {
|
|
||||||
if v.original {
|
|
||||||
v.str(node.Original)
|
|
||||||
} else {
|
|
||||||
v.str(fmt.Sprintf("BOOLEAN{%s}", node.Canonical()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitNumber implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitNumber(node *NumberLiteral) interface{} {
|
|
||||||
if v.original {
|
|
||||||
v.str(node.Original)
|
|
||||||
} else {
|
|
||||||
v.str(fmt.Sprintf("NUMBER{%s}", node.Canonical()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Miscellaneous
|
|
||||||
|
|
||||||
// VisitHash implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitHash(node *Hash) interface{} {
|
|
||||||
v.str("HASH{")
|
|
||||||
|
|
||||||
for i, p := range node.Pairs {
|
|
||||||
if i > 0 {
|
|
||||||
v.str(", ")
|
|
||||||
}
|
|
||||||
p.Accept(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
v.str("}")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisitHashPair implements corresponding Visitor interface method
|
|
||||||
func (v *printVisitor) VisitHashPair(node *HashPair) interface{} {
|
|
||||||
v.str(node.Key + "=")
|
|
||||||
node.Val.Accept(v)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
95
vendor/github.com/aymerick/raymond/data_frame.go
generated
vendored
95
vendor/github.com/aymerick/raymond/data_frame.go
generated
vendored
@ -1,95 +0,0 @@
|
|||||||
package raymond
|
|
||||||
|
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
// DataFrame represents a private data frame.
|
|
||||||
//
|
|
||||||
// Cf. private variables documentation at: http://handlebarsjs.com/block_helpers.html
|
|
||||||
type DataFrame struct {
|
|
||||||
parent *DataFrame
|
|
||||||
data map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDataFrame instanciates a new private data frame.
|
|
||||||
func NewDataFrame() *DataFrame {
|
|
||||||
return &DataFrame{
|
|
||||||
data: make(map[string]interface{}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy instanciates a new private data frame with receiver as parent.
|
|
||||||
func (p *DataFrame) Copy() *DataFrame {
|
|
||||||
result := NewDataFrame()
|
|
||||||
|
|
||||||
for k, v := range p.data {
|
|
||||||
result.data[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
result.parent = p
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// newIterDataFrame instanciates a new private data frame with receiver as parent and with iteration data set (@index, @key, @first, @last)
|
|
||||||
func (p *DataFrame) newIterDataFrame(length int, i int, key interface{}) *DataFrame {
|
|
||||||
result := p.Copy()
|
|
||||||
|
|
||||||
result.Set("index", i)
|
|
||||||
result.Set("key", key)
|
|
||||||
result.Set("first", i == 0)
|
|
||||||
result.Set("last", i == length-1)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set sets a data value.
|
|
||||||
func (p *DataFrame) Set(key string, val interface{}) {
|
|
||||||
p.data[key] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get gets a data value.
|
|
||||||
func (p *DataFrame) Get(key string) interface{} {
|
|
||||||
return p.find([]string{key})
|
|
||||||
}
|
|
||||||
|
|
||||||
// find gets a deep data value
|
|
||||||
//
|
|
||||||
// @todo This is NOT consistent with the way we resolve data in template (cf. `evalDataPathExpression()`) ! FIX THAT !
|
|
||||||
func (p *DataFrame) find(parts []string) interface{} {
|
|
||||||
data := p.data
|
|
||||||
|
|
||||||
for i, part := range parts {
|
|
||||||
val := data[part]
|
|
||||||
if val == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if i == len(parts)-1 {
|
|
||||||
// found
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
|
|
||||||
valValue := reflect.ValueOf(val)
|
|
||||||
if valValue.Kind() != reflect.Map {
|
|
||||||
// not found
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// continue
|
|
||||||
data = mapStringInterface(valValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// not found
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// mapStringInterface converts any `map` to `map[string]interface{}`
|
|
||||||
func mapStringInterface(value reflect.Value) map[string]interface{} {
|
|
||||||
result := make(map[string]interface{})
|
|
||||||
|
|
||||||
for _, key := range value.MapKeys() {
|
|
||||||
result[strValue(key)] = value.MapIndex(key).Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
65
vendor/github.com/aymerick/raymond/escape.go
generated
vendored
65
vendor/github.com/aymerick/raymond/escape.go
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
package raymond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
//
|
|
||||||
// That whole file is borrowed from https://github.com/golang/go/tree/master/src/html/escape.go
|
|
||||||
//
|
|
||||||
// With changes:
|
|
||||||
// ' => '
|
|
||||||
// " => "
|
|
||||||
//
|
|
||||||
// To stay in sync with JS implementation, and make mustache tests pass.
|
|
||||||
//
|
|
||||||
|
|
||||||
type writer interface {
|
|
||||||
WriteString(string) (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
const escapedChars = `&'<>"`
|
|
||||||
|
|
||||||
func escape(w writer, s string) error {
|
|
||||||
i := strings.IndexAny(s, escapedChars)
|
|
||||||
for i != -1 {
|
|
||||||
if _, err := w.WriteString(s[:i]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var esc string
|
|
||||||
switch s[i] {
|
|
||||||
case '&':
|
|
||||||
esc = "&"
|
|
||||||
case '\'':
|
|
||||||
esc = "'"
|
|
||||||
case '<':
|
|
||||||
esc = "<"
|
|
||||||
case '>':
|
|
||||||
esc = ">"
|
|
||||||
case '"':
|
|
||||||
esc = """
|
|
||||||
default:
|
|
||||||
panic("unrecognized escape character")
|
|
||||||
}
|
|
||||||
s = s[i+1:]
|
|
||||||
if _, err := w.WriteString(esc); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
i = strings.IndexAny(s, escapedChars)
|
|
||||||
}
|
|
||||||
_, err := w.WriteString(s)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Escape escapes special HTML characters.
|
|
||||||
//
|
|
||||||
// It can be used by helpers that return a SafeString and that need to escape some content by themselves.
|
|
||||||
func Escape(s string) string {
|
|
||||||
if strings.IndexAny(s, escapedChars) == -1 {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
|
||||||
escape(&buf, s)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
1005
vendor/github.com/aymerick/raymond/eval.go
generated
vendored
1005
vendor/github.com/aymerick/raymond/eval.go
generated
vendored
File diff suppressed because it is too large
Load Diff
382
vendor/github.com/aymerick/raymond/helper.go
generated
vendored
382
vendor/github.com/aymerick/raymond/helper.go
generated
vendored
@ -1,382 +0,0 @@
|
|||||||
package raymond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"reflect"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options represents the options argument provided to helpers and context functions.
|
|
||||||
type Options struct {
|
|
||||||
// evaluation visitor
|
|
||||||
eval *evalVisitor
|
|
||||||
|
|
||||||
// params
|
|
||||||
params []interface{}
|
|
||||||
hash map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// helpers stores all globally registered helpers
|
|
||||||
var helpers = make(map[string]reflect.Value)
|
|
||||||
|
|
||||||
// protects global helpers
|
|
||||||
var helpersMutex sync.RWMutex
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// register builtin helpers
|
|
||||||
RegisterHelper("if", ifHelper)
|
|
||||||
RegisterHelper("unless", unlessHelper)
|
|
||||||
RegisterHelper("with", withHelper)
|
|
||||||
RegisterHelper("each", eachHelper)
|
|
||||||
RegisterHelper("log", logHelper)
|
|
||||||
RegisterHelper("lookup", lookupHelper)
|
|
||||||
RegisterHelper("equal", equalHelper)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterHelper registers a global helper. That helper will be available to all templates.
|
|
||||||
func RegisterHelper(name string, helper interface{}) {
|
|
||||||
helpersMutex.Lock()
|
|
||||||
defer helpersMutex.Unlock()
|
|
||||||
|
|
||||||
if helpers[name] != zero {
|
|
||||||
panic(fmt.Errorf("Helper already registered: %s", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
val := reflect.ValueOf(helper)
|
|
||||||
ensureValidHelper(name, val)
|
|
||||||
|
|
||||||
helpers[name] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterHelpers registers several global helpers. Those helpers will be available to all templates.
|
|
||||||
func RegisterHelpers(helpers map[string]interface{}) {
|
|
||||||
for name, helper := range helpers {
|
|
||||||
RegisterHelper(name, helper)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensureValidHelper panics if given helper is not valid
|
|
||||||
func ensureValidHelper(name string, funcValue reflect.Value) {
|
|
||||||
if funcValue.Kind() != reflect.Func {
|
|
||||||
panic(fmt.Errorf("Helper must be a function: %s", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
funcType := funcValue.Type()
|
|
||||||
|
|
||||||
if funcType.NumOut() != 1 {
|
|
||||||
panic(fmt.Errorf("Helper function must return a string or a SafeString: %s", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo Check if first returned value is a string, SafeString or interface{} ?
|
|
||||||
}
|
|
||||||
|
|
||||||
// findHelper finds a globally registered helper
|
|
||||||
func findHelper(name string) reflect.Value {
|
|
||||||
helpersMutex.RLock()
|
|
||||||
defer helpersMutex.RUnlock()
|
|
||||||
|
|
||||||
return helpers[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// newOptions instanciates a new Options
|
|
||||||
func newOptions(eval *evalVisitor, params []interface{}, hash map[string]interface{}) *Options {
|
|
||||||
return &Options{
|
|
||||||
eval: eval,
|
|
||||||
params: params,
|
|
||||||
hash: hash,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// newEmptyOptions instanciates a new empty Options
|
|
||||||
func newEmptyOptions(eval *evalVisitor) *Options {
|
|
||||||
return &Options{
|
|
||||||
eval: eval,
|
|
||||||
hash: make(map[string]interface{}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Context Values
|
|
||||||
//
|
|
||||||
|
|
||||||
// Value returns field value from current context.
|
|
||||||
func (options *Options) Value(name string) interface{} {
|
|
||||||
value := options.eval.evalField(options.eval.curCtx(), name, false)
|
|
||||||
if !value.IsValid() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValueStr returns string representation of field value from current context.
|
|
||||||
func (options *Options) ValueStr(name string) string {
|
|
||||||
return Str(options.Value(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ctx returns current evaluation context.
|
|
||||||
func (options *Options) Ctx() interface{} {
|
|
||||||
return options.eval.curCtx().Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Hash Arguments
|
|
||||||
//
|
|
||||||
|
|
||||||
// HashProp returns hash property.
|
|
||||||
func (options *Options) HashProp(name string) interface{} {
|
|
||||||
return options.hash[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// HashStr returns string representation of hash property.
|
|
||||||
func (options *Options) HashStr(name string) string {
|
|
||||||
return Str(options.hash[name])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns entire hash.
|
|
||||||
func (options *Options) Hash() map[string]interface{} {
|
|
||||||
return options.hash
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Parameters
|
|
||||||
//
|
|
||||||
|
|
||||||
// Param returns parameter at given position.
|
|
||||||
func (options *Options) Param(pos int) interface{} {
|
|
||||||
if len(options.params) > pos {
|
|
||||||
return options.params[pos]
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParamStr returns string representation of parameter at given position.
|
|
||||||
func (options *Options) ParamStr(pos int) string {
|
|
||||||
return Str(options.Param(pos))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params returns all parameters.
|
|
||||||
func (options *Options) Params() []interface{} {
|
|
||||||
return options.params
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Private data
|
|
||||||
//
|
|
||||||
|
|
||||||
// Data returns private data value.
|
|
||||||
func (options *Options) Data(name string) interface{} {
|
|
||||||
return options.eval.dataFrame.Get(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataStr returns string representation of private data value.
|
|
||||||
func (options *Options) DataStr(name string) string {
|
|
||||||
return Str(options.eval.dataFrame.Get(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataFrame returns current private data frame.
|
|
||||||
func (options *Options) DataFrame() *DataFrame {
|
|
||||||
return options.eval.dataFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDataFrame instanciates a new data frame that is a copy of current evaluation data frame.
|
|
||||||
//
|
|
||||||
// Parent of returned data frame is set to current evaluation data frame.
|
|
||||||
func (options *Options) NewDataFrame() *DataFrame {
|
|
||||||
return options.eval.dataFrame.Copy()
|
|
||||||
}
|
|
||||||
|
|
||||||
// newIterDataFrame instanciates a new data frame and set iteration specific vars
|
|
||||||
func (options *Options) newIterDataFrame(length int, i int, key interface{}) *DataFrame {
|
|
||||||
return options.eval.dataFrame.newIterDataFrame(length, i, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Evaluation
|
|
||||||
//
|
|
||||||
|
|
||||||
// evalBlock evaluates block with given context, private data and iteration key
|
|
||||||
func (options *Options) evalBlock(ctx interface{}, data *DataFrame, key interface{}) string {
|
|
||||||
result := ""
|
|
||||||
|
|
||||||
if block := options.eval.curBlock(); (block != nil) && (block.Program != nil) {
|
|
||||||
result = options.eval.evalProgram(block.Program, ctx, data, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fn evaluates block with current evaluation context.
|
|
||||||
func (options *Options) Fn() string {
|
|
||||||
return options.evalBlock(nil, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FnCtxData evaluates block with given context and private data frame.
|
|
||||||
func (options *Options) FnCtxData(ctx interface{}, data *DataFrame) string {
|
|
||||||
return options.evalBlock(ctx, data, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FnWith evaluates block with given context.
|
|
||||||
func (options *Options) FnWith(ctx interface{}) string {
|
|
||||||
return options.evalBlock(ctx, nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FnData evaluates block with given private data frame.
|
|
||||||
func (options *Options) FnData(data *DataFrame) string {
|
|
||||||
return options.evalBlock(nil, data, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inverse evaluates "else block".
|
|
||||||
func (options *Options) Inverse() string {
|
|
||||||
result := ""
|
|
||||||
if block := options.eval.curBlock(); (block != nil) && (block.Inverse != nil) {
|
|
||||||
result, _ = block.Inverse.Accept(options.eval).(string)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eval evaluates field for given context.
|
|
||||||
func (options *Options) Eval(ctx interface{}, field string) interface{} {
|
|
||||||
if ctx == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if field == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
val := options.eval.evalField(reflect.ValueOf(ctx), field, false)
|
|
||||||
if !val.IsValid() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return val.Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Misc
|
|
||||||
//
|
|
||||||
|
|
||||||
// isIncludableZero returns true if 'includeZero' option is set and first param is the number 0
|
|
||||||
func (options *Options) isIncludableZero() bool {
|
|
||||||
b, ok := options.HashProp("includeZero").(bool)
|
|
||||||
if ok && b {
|
|
||||||
nb, ok := options.Param(0).(int)
|
|
||||||
if ok && nb == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Builtin helpers
|
|
||||||
//
|
|
||||||
|
|
||||||
// #if block helper
|
|
||||||
func ifHelper(conditional interface{}, options *Options) interface{} {
|
|
||||||
if options.isIncludableZero() || IsTrue(conditional) {
|
|
||||||
return options.Fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
// #unless block helper
|
|
||||||
func unlessHelper(conditional interface{}, options *Options) interface{} {
|
|
||||||
if options.isIncludableZero() || IsTrue(conditional) {
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
return options.Fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
// #with block helper
|
|
||||||
func withHelper(context interface{}, options *Options) interface{} {
|
|
||||||
if IsTrue(context) {
|
|
||||||
return options.FnWith(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
// #each block helper
|
|
||||||
func eachHelper(context interface{}, options *Options) interface{} {
|
|
||||||
if !IsTrue(context) {
|
|
||||||
return options.Inverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
result := ""
|
|
||||||
|
|
||||||
val := reflect.ValueOf(context)
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Array, reflect.Slice:
|
|
||||||
for i := 0; i < val.Len(); i++ {
|
|
||||||
// computes private data
|
|
||||||
data := options.newIterDataFrame(val.Len(), i, nil)
|
|
||||||
|
|
||||||
// evaluates block
|
|
||||||
result += options.evalBlock(val.Index(i).Interface(), data, i)
|
|
||||||
}
|
|
||||||
case reflect.Map:
|
|
||||||
// note: a go hash is not ordered, so result may vary, this behaviour differs from the JS implementation
|
|
||||||
keys := val.MapKeys()
|
|
||||||
for i := 0; i < len(keys); i++ {
|
|
||||||
key := keys[i].Interface()
|
|
||||||
ctx := val.MapIndex(keys[i]).Interface()
|
|
||||||
|
|
||||||
// computes private data
|
|
||||||
data := options.newIterDataFrame(len(keys), i, key)
|
|
||||||
|
|
||||||
// evaluates block
|
|
||||||
result += options.evalBlock(ctx, data, key)
|
|
||||||
}
|
|
||||||
case reflect.Struct:
|
|
||||||
var exportedFields []int
|
|
||||||
|
|
||||||
// collect exported fields only
|
|
||||||
for i := 0; i < val.NumField(); i++ {
|
|
||||||
if tField := val.Type().Field(i); tField.PkgPath == "" {
|
|
||||||
exportedFields = append(exportedFields, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, fieldIndex := range exportedFields {
|
|
||||||
key := val.Type().Field(fieldIndex).Name
|
|
||||||
ctx := val.Field(fieldIndex).Interface()
|
|
||||||
|
|
||||||
// computes private data
|
|
||||||
data := options.newIterDataFrame(len(exportedFields), i, key)
|
|
||||||
|
|
||||||
// evaluates block
|
|
||||||
result += options.evalBlock(ctx, data, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// #log helper
|
|
||||||
func logHelper(message string) interface{} {
|
|
||||||
log.Print(message)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// #lookup helper
|
|
||||||
func lookupHelper(obj interface{}, field string, options *Options) interface{} {
|
|
||||||
return Str(options.Eval(obj, field))
|
|
||||||
}
|
|
||||||
|
|
||||||
// #equal helper
|
|
||||||
// Ref: https://github.com/aymerick/raymond/issues/7
|
|
||||||
func equalHelper(a interface{}, b interface{}, options *Options) interface{} {
|
|
||||||
if Str(a) == Str(b) {
|
|
||||||
return options.Fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
639
vendor/github.com/aymerick/raymond/lexer/lexer.go
generated
vendored
639
vendor/github.com/aymerick/raymond/lexer/lexer.go
generated
vendored
@ -1,639 +0,0 @@
|
|||||||
// Package lexer provides a handlebars tokenizer.
|
|
||||||
package lexer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// References:
|
|
||||||
// - https://github.com/wycats/handlebars.js/blob/master/src/handlebars.l
|
|
||||||
// - https://github.com/golang/go/blob/master/src/text/template/parse/lex.go
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Mustaches detection
|
|
||||||
escapedEscapedOpenMustache = "\\\\{{"
|
|
||||||
escapedOpenMustache = "\\{{"
|
|
||||||
openMustache = "{{"
|
|
||||||
closeMustache = "}}"
|
|
||||||
closeStripMustache = "~}}"
|
|
||||||
closeUnescapedStripMustache = "}~}}"
|
|
||||||
)
|
|
||||||
|
|
||||||
const eof = -1
|
|
||||||
|
|
||||||
// lexFunc represents a function that returns the next lexer function.
|
|
||||||
type lexFunc func(*Lexer) lexFunc
|
|
||||||
|
|
||||||
// Lexer is a lexical analyzer.
|
|
||||||
type Lexer struct {
|
|
||||||
input string // input to scan
|
|
||||||
name string // lexer name, used for testing purpose
|
|
||||||
tokens chan Token // channel of scanned tokens
|
|
||||||
nextFunc lexFunc // the next function to execute
|
|
||||||
|
|
||||||
pos int // current byte position in input string
|
|
||||||
line int // current line position in input string
|
|
||||||
width int // size of last rune scanned from input string
|
|
||||||
start int // start position of the token we are scanning
|
|
||||||
|
|
||||||
// the shameful contextual properties needed because `nextFunc` is not enough
|
|
||||||
closeComment *regexp.Regexp // regexp to scan close of current comment
|
|
||||||
rawBlock bool // are we parsing a raw block content ?
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
lookheadChars = `[\s` + regexp.QuoteMeta("=~}/)|") + `]`
|
|
||||||
literalLookheadChars = `[\s` + regexp.QuoteMeta("~})") + `]`
|
|
||||||
|
|
||||||
// characters not allowed in an identifier
|
|
||||||
unallowedIDChars = " \n\t!\"#%&'()*+,./;<=>@[\\]^`{|}~"
|
|
||||||
|
|
||||||
// regular expressions
|
|
||||||
rID = regexp.MustCompile(`^[^` + regexp.QuoteMeta(unallowedIDChars) + `]+`)
|
|
||||||
rDotID = regexp.MustCompile(`^\.` + lookheadChars)
|
|
||||||
rTrue = regexp.MustCompile(`^true` + literalLookheadChars)
|
|
||||||
rFalse = regexp.MustCompile(`^false` + literalLookheadChars)
|
|
||||||
rOpenRaw = regexp.MustCompile(`^\{\{\{\{`)
|
|
||||||
rCloseRaw = regexp.MustCompile(`^\}\}\}\}`)
|
|
||||||
rOpenEndRaw = regexp.MustCompile(`^\{\{\{\{/`)
|
|
||||||
rOpenEndRawLookAhead = regexp.MustCompile(`\{\{\{\{/`)
|
|
||||||
rOpenUnescaped = regexp.MustCompile(`^\{\{~?\{`)
|
|
||||||
rCloseUnescaped = regexp.MustCompile(`^\}~?\}\}`)
|
|
||||||
rOpenBlock = regexp.MustCompile(`^\{\{~?#`)
|
|
||||||
rOpenEndBlock = regexp.MustCompile(`^\{\{~?/`)
|
|
||||||
rOpenPartial = regexp.MustCompile(`^\{\{~?>`)
|
|
||||||
// {{^}} or {{else}}
|
|
||||||
rInverse = regexp.MustCompile(`^(\{\{~?\^\s*~?\}\}|\{\{~?\s*else\s*~?\}\})`)
|
|
||||||
rOpenInverse = regexp.MustCompile(`^\{\{~?\^`)
|
|
||||||
rOpenInverseChain = regexp.MustCompile(`^\{\{~?\s*else`)
|
|
||||||
// {{ or {{&
|
|
||||||
rOpen = regexp.MustCompile(`^\{\{~?&?`)
|
|
||||||
rClose = regexp.MustCompile(`^~?\}\}`)
|
|
||||||
rOpenBlockParams = regexp.MustCompile(`^as\s+\|`)
|
|
||||||
// {{!-- ... --}}
|
|
||||||
rOpenCommentDash = regexp.MustCompile(`^\{\{~?!--\s*`)
|
|
||||||
rCloseCommentDash = regexp.MustCompile(`^\s*--~?\}\}`)
|
|
||||||
// {{! ... }}
|
|
||||||
rOpenComment = regexp.MustCompile(`^\{\{~?!\s*`)
|
|
||||||
rCloseComment = regexp.MustCompile(`^\s*~?\}\}`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Scan scans given input.
|
|
||||||
//
|
|
||||||
// Tokens can then be fetched sequentially thanks to NextToken() function on returned lexer.
|
|
||||||
func Scan(input string) *Lexer {
|
|
||||||
return scanWithName(input, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanWithName scans given input, with a name used for testing
|
|
||||||
//
|
|
||||||
// Tokens can then be fetched sequentially thanks to NextToken() function on returned lexer.
|
|
||||||
func scanWithName(input string, name string) *Lexer {
|
|
||||||
result := &Lexer{
|
|
||||||
input: input,
|
|
||||||
name: name,
|
|
||||||
tokens: make(chan Token),
|
|
||||||
line: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
go result.run()
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect scans and collect all tokens.
|
|
||||||
//
|
|
||||||
// This should be used for debugging purpose only. You should use Scan() and lexer.NextToken() functions instead.
|
|
||||||
func Collect(input string) []Token {
|
|
||||||
var result []Token
|
|
||||||
|
|
||||||
l := Scan(input)
|
|
||||||
for {
|
|
||||||
token := l.NextToken()
|
|
||||||
result = append(result, token)
|
|
||||||
|
|
||||||
if token.Kind == TokenEOF || token.Kind == TokenError {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// NextToken returns the next scanned token.
|
|
||||||
func (l *Lexer) NextToken() Token {
|
|
||||||
result := <-l.tokens
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// run starts lexical analysis
|
|
||||||
func (l *Lexer) run() {
|
|
||||||
for l.nextFunc = lexContent; l.nextFunc != nil; {
|
|
||||||
l.nextFunc = l.nextFunc(l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// next returns next character from input, or eof of there is nothing left to scan
|
|
||||||
func (l *Lexer) next() rune {
|
|
||||||
if l.pos >= len(l.input) {
|
|
||||||
l.width = 0
|
|
||||||
return eof
|
|
||||||
}
|
|
||||||
|
|
||||||
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
|
|
||||||
l.width = w
|
|
||||||
l.pos += l.width
|
|
||||||
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Lexer) produce(kind TokenKind, val string) {
|
|
||||||
l.tokens <- Token{kind, val, l.start, l.line}
|
|
||||||
|
|
||||||
// scanning a new token
|
|
||||||
l.start = l.pos
|
|
||||||
|
|
||||||
// update line number
|
|
||||||
l.line += strings.Count(val, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// emit emits a new scanned token
|
|
||||||
func (l *Lexer) emit(kind TokenKind) {
|
|
||||||
l.produce(kind, l.input[l.start:l.pos])
|
|
||||||
}
|
|
||||||
|
|
||||||
// emitContent emits scanned content
|
|
||||||
func (l *Lexer) emitContent() {
|
|
||||||
if l.pos > l.start {
|
|
||||||
l.emit(TokenContent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// emitString emits a scanned string
|
|
||||||
func (l *Lexer) emitString(delimiter rune) {
|
|
||||||
str := l.input[l.start:l.pos]
|
|
||||||
|
|
||||||
// replace escaped delimiters
|
|
||||||
str = strings.Replace(str, "\\"+string(delimiter), string(delimiter), -1)
|
|
||||||
|
|
||||||
l.produce(TokenString, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// peek returns but does not consume the next character in the input
|
|
||||||
func (l *Lexer) peek() rune {
|
|
||||||
r := l.next()
|
|
||||||
l.backup()
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// backup steps back one character
|
|
||||||
//
|
|
||||||
// WARNING: Can only be called once per call of next
|
|
||||||
func (l *Lexer) backup() {
|
|
||||||
l.pos -= l.width
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignoreskips all characters that have been scanned up to current position
|
|
||||||
func (l *Lexer) ignore() {
|
|
||||||
l.start = l.pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// accept scans the next character if it is included in given string
|
|
||||||
func (l *Lexer) accept(valid string) bool {
|
|
||||||
if strings.IndexRune(valid, l.next()) >= 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
l.backup()
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// acceptRun scans all following characters that are part of given string
|
|
||||||
func (l *Lexer) acceptRun(valid string) {
|
|
||||||
for strings.IndexRune(valid, l.next()) >= 0 {
|
|
||||||
}
|
|
||||||
|
|
||||||
l.backup()
|
|
||||||
}
|
|
||||||
|
|
||||||
// errorf emits an error token
|
|
||||||
func (l *Lexer) errorf(format string, args ...interface{}) lexFunc {
|
|
||||||
l.tokens <- Token{TokenError, fmt.Sprintf(format, args...), l.start, l.line}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isString returns true if content at current scanning position starts with given string
|
|
||||||
func (l *Lexer) isString(str string) bool {
|
|
||||||
return strings.HasPrefix(l.input[l.pos:], str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// findRegexp returns the first string from current scanning position that matches given regular expression
|
|
||||||
func (l *Lexer) findRegexp(r *regexp.Regexp) string {
|
|
||||||
return r.FindString(l.input[l.pos:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// indexRegexp returns the index of the first string from current scanning position that matches given regular expression
|
|
||||||
//
|
|
||||||
// It returns -1 if not found
|
|
||||||
func (l *Lexer) indexRegexp(r *regexp.Regexp) int {
|
|
||||||
loc := r.FindStringIndex(l.input[l.pos:])
|
|
||||||
if loc == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return loc[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexContent scans content (ie: not between mustaches)
|
|
||||||
func lexContent(l *Lexer) lexFunc {
|
|
||||||
var next lexFunc
|
|
||||||
|
|
||||||
if l.rawBlock {
|
|
||||||
if i := l.indexRegexp(rOpenEndRawLookAhead); i != -1 {
|
|
||||||
// {{{{/
|
|
||||||
l.rawBlock = false
|
|
||||||
l.pos += i
|
|
||||||
|
|
||||||
next = lexOpenMustache
|
|
||||||
} else {
|
|
||||||
return l.errorf("Unclosed raw block")
|
|
||||||
}
|
|
||||||
} else if l.isString(escapedEscapedOpenMustache) {
|
|
||||||
// \\{{
|
|
||||||
|
|
||||||
// emit content with only one escaped escape
|
|
||||||
l.next()
|
|
||||||
l.emitContent()
|
|
||||||
|
|
||||||
// ignore second escaped escape
|
|
||||||
l.next()
|
|
||||||
l.ignore()
|
|
||||||
|
|
||||||
next = lexContent
|
|
||||||
} else if l.isString(escapedOpenMustache) {
|
|
||||||
// \{{
|
|
||||||
next = lexEscapedOpenMustache
|
|
||||||
} else if str := l.findRegexp(rOpenCommentDash); str != "" {
|
|
||||||
// {{!--
|
|
||||||
l.closeComment = rCloseCommentDash
|
|
||||||
|
|
||||||
next = lexComment
|
|
||||||
} else if str := l.findRegexp(rOpenComment); str != "" {
|
|
||||||
// {{!
|
|
||||||
l.closeComment = rCloseComment
|
|
||||||
|
|
||||||
next = lexComment
|
|
||||||
} else if l.isString(openMustache) {
|
|
||||||
// {{
|
|
||||||
next = lexOpenMustache
|
|
||||||
}
|
|
||||||
|
|
||||||
if next != nil {
|
|
||||||
// emit scanned content
|
|
||||||
l.emitContent()
|
|
||||||
|
|
||||||
// scan next token
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan next rune
|
|
||||||
if l.next() == eof {
|
|
||||||
// emit scanned content
|
|
||||||
l.emitContent()
|
|
||||||
|
|
||||||
// this is over
|
|
||||||
l.emit(TokenEOF)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// continue content scanning
|
|
||||||
return lexContent
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexEscapedOpenMustache scans \{{
|
|
||||||
func lexEscapedOpenMustache(l *Lexer) lexFunc {
|
|
||||||
// ignore escape character
|
|
||||||
l.next()
|
|
||||||
l.ignore()
|
|
||||||
|
|
||||||
// scan mustaches
|
|
||||||
for l.peek() == '{' {
|
|
||||||
l.next()
|
|
||||||
}
|
|
||||||
|
|
||||||
return lexContent
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexOpenMustache scans {{
|
|
||||||
func lexOpenMustache(l *Lexer) lexFunc {
|
|
||||||
var str string
|
|
||||||
var tok TokenKind
|
|
||||||
|
|
||||||
nextFunc := lexExpression
|
|
||||||
|
|
||||||
if str = l.findRegexp(rOpenEndRaw); str != "" {
|
|
||||||
tok = TokenOpenEndRawBlock
|
|
||||||
} else if str = l.findRegexp(rOpenRaw); str != "" {
|
|
||||||
tok = TokenOpenRawBlock
|
|
||||||
l.rawBlock = true
|
|
||||||
} else if str = l.findRegexp(rOpenUnescaped); str != "" {
|
|
||||||
tok = TokenOpenUnescaped
|
|
||||||
} else if str = l.findRegexp(rOpenBlock); str != "" {
|
|
||||||
tok = TokenOpenBlock
|
|
||||||
} else if str = l.findRegexp(rOpenEndBlock); str != "" {
|
|
||||||
tok = TokenOpenEndBlock
|
|
||||||
} else if str = l.findRegexp(rOpenPartial); str != "" {
|
|
||||||
tok = TokenOpenPartial
|
|
||||||
} else if str = l.findRegexp(rInverse); str != "" {
|
|
||||||
tok = TokenInverse
|
|
||||||
nextFunc = lexContent
|
|
||||||
} else if str = l.findRegexp(rOpenInverse); str != "" {
|
|
||||||
tok = TokenOpenInverse
|
|
||||||
} else if str = l.findRegexp(rOpenInverseChain); str != "" {
|
|
||||||
tok = TokenOpenInverseChain
|
|
||||||
} else if str = l.findRegexp(rOpen); str != "" {
|
|
||||||
tok = TokenOpen
|
|
||||||
} else {
|
|
||||||
// this is rotten
|
|
||||||
panic("Current pos MUST be an opening mustache")
|
|
||||||
}
|
|
||||||
|
|
||||||
l.pos += len(str)
|
|
||||||
l.emit(tok)
|
|
||||||
|
|
||||||
return nextFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexCloseMustache scans }} or ~}}
|
|
||||||
func lexCloseMustache(l *Lexer) lexFunc {
|
|
||||||
var str string
|
|
||||||
var tok TokenKind
|
|
||||||
|
|
||||||
if str = l.findRegexp(rCloseRaw); str != "" {
|
|
||||||
// }}}}
|
|
||||||
tok = TokenCloseRawBlock
|
|
||||||
} else if str = l.findRegexp(rCloseUnescaped); str != "" {
|
|
||||||
// }}}
|
|
||||||
tok = TokenCloseUnescaped
|
|
||||||
} else if str = l.findRegexp(rClose); str != "" {
|
|
||||||
// }}
|
|
||||||
tok = TokenClose
|
|
||||||
} else {
|
|
||||||
// this is rotten
|
|
||||||
panic("Current pos MUST be a closing mustache")
|
|
||||||
}
|
|
||||||
|
|
||||||
l.pos += len(str)
|
|
||||||
l.emit(tok)
|
|
||||||
|
|
||||||
return lexContent
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexExpression scans inside mustaches
|
|
||||||
func lexExpression(l *Lexer) lexFunc {
|
|
||||||
// search close mustache delimiter
|
|
||||||
if l.isString(closeMustache) || l.isString(closeStripMustache) || l.isString(closeUnescapedStripMustache) {
|
|
||||||
return lexCloseMustache
|
|
||||||
}
|
|
||||||
|
|
||||||
// search some patterns before advancing scanning position
|
|
||||||
|
|
||||||
// "as |"
|
|
||||||
if str := l.findRegexp(rOpenBlockParams); str != "" {
|
|
||||||
l.pos += len(str)
|
|
||||||
l.emit(TokenOpenBlockParams)
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// ..
|
|
||||||
if l.isString("..") {
|
|
||||||
l.pos += len("..")
|
|
||||||
l.emit(TokenID)
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// .
|
|
||||||
if str := l.findRegexp(rDotID); str != "" {
|
|
||||||
l.pos += len(".")
|
|
||||||
l.emit(TokenID)
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// true
|
|
||||||
if str := l.findRegexp(rTrue); str != "" {
|
|
||||||
l.pos += len("true")
|
|
||||||
l.emit(TokenBoolean)
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// false
|
|
||||||
if str := l.findRegexp(rFalse); str != "" {
|
|
||||||
l.pos += len("false")
|
|
||||||
l.emit(TokenBoolean)
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// let's scan next character
|
|
||||||
switch r := l.next(); {
|
|
||||||
case r == eof:
|
|
||||||
return l.errorf("Unclosed expression")
|
|
||||||
case isIgnorable(r):
|
|
||||||
return lexIgnorable
|
|
||||||
case r == '(':
|
|
||||||
l.emit(TokenOpenSexpr)
|
|
||||||
case r == ')':
|
|
||||||
l.emit(TokenCloseSexpr)
|
|
||||||
case r == '=':
|
|
||||||
l.emit(TokenEquals)
|
|
||||||
case r == '@':
|
|
||||||
l.emit(TokenData)
|
|
||||||
case r == '"' || r == '\'':
|
|
||||||
l.backup()
|
|
||||||
return lexString
|
|
||||||
case r == '/' || r == '.':
|
|
||||||
l.emit(TokenSep)
|
|
||||||
case r == '|':
|
|
||||||
l.emit(TokenCloseBlockParams)
|
|
||||||
case r == '+' || r == '-' || (r >= '0' && r <= '9'):
|
|
||||||
l.backup()
|
|
||||||
return lexNumber
|
|
||||||
case r == '[':
|
|
||||||
return lexPathLiteral
|
|
||||||
case strings.IndexRune(unallowedIDChars, r) < 0:
|
|
||||||
l.backup()
|
|
||||||
return lexIdentifier
|
|
||||||
default:
|
|
||||||
return l.errorf("Unexpected character in expression: '%c'", r)
|
|
||||||
}
|
|
||||||
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexComment scans {{!-- or {{!
|
|
||||||
func lexComment(l *Lexer) lexFunc {
|
|
||||||
if str := l.findRegexp(l.closeComment); str != "" {
|
|
||||||
l.pos += len(str)
|
|
||||||
l.emit(TokenComment)
|
|
||||||
|
|
||||||
return lexContent
|
|
||||||
}
|
|
||||||
|
|
||||||
if r := l.next(); r == eof {
|
|
||||||
return l.errorf("Unclosed comment")
|
|
||||||
}
|
|
||||||
|
|
||||||
return lexComment
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexIgnorable scans all following ignorable characters
|
|
||||||
func lexIgnorable(l *Lexer) lexFunc {
|
|
||||||
for isIgnorable(l.peek()) {
|
|
||||||
l.next()
|
|
||||||
}
|
|
||||||
l.ignore()
|
|
||||||
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexString scans a string
|
|
||||||
func lexString(l *Lexer) lexFunc {
|
|
||||||
// get string delimiter
|
|
||||||
delim := l.next()
|
|
||||||
var prev rune
|
|
||||||
|
|
||||||
// ignore delimiter
|
|
||||||
l.ignore()
|
|
||||||
|
|
||||||
for {
|
|
||||||
r := l.next()
|
|
||||||
if r == eof || r == '\n' {
|
|
||||||
return l.errorf("Unterminated string")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r == delim) && (prev != '\\') {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = r
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove end delimiter
|
|
||||||
l.backup()
|
|
||||||
|
|
||||||
// emit string
|
|
||||||
l.emitString(delim)
|
|
||||||
|
|
||||||
// skip end delimiter
|
|
||||||
l.next()
|
|
||||||
l.ignore()
|
|
||||||
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This
|
|
||||||
// isn't a perfect number scanner - for instance it accepts "." and "0x0.2"
|
|
||||||
// and "089" - but when it's wrong the input is invalid and the parser (via
|
|
||||||
// strconv) will notice.
|
|
||||||
//
|
|
||||||
// NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/parse/lex.go
|
|
||||||
func lexNumber(l *Lexer) lexFunc {
|
|
||||||
if !l.scanNumber() {
|
|
||||||
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
|
||||||
}
|
|
||||||
if sign := l.peek(); sign == '+' || sign == '-' {
|
|
||||||
// Complex: 1+2i. No spaces, must end in 'i'.
|
|
||||||
if !l.scanNumber() || l.input[l.pos-1] != 'i' {
|
|
||||||
return l.errorf("bad number syntax: %q", l.input[l.start:l.pos])
|
|
||||||
}
|
|
||||||
l.emit(TokenNumber)
|
|
||||||
} else {
|
|
||||||
l.emit(TokenNumber)
|
|
||||||
}
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanNumber scans a number
|
|
||||||
//
|
|
||||||
// NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/parse/lex.go
|
|
||||||
func (l *Lexer) scanNumber() bool {
|
|
||||||
// Optional leading sign.
|
|
||||||
l.accept("+-")
|
|
||||||
|
|
||||||
// Is it hex?
|
|
||||||
digits := "0123456789"
|
|
||||||
|
|
||||||
if l.accept("0") && l.accept("xX") {
|
|
||||||
digits = "0123456789abcdefABCDEF"
|
|
||||||
}
|
|
||||||
|
|
||||||
l.acceptRun(digits)
|
|
||||||
|
|
||||||
if l.accept(".") {
|
|
||||||
l.acceptRun(digits)
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.accept("eE") {
|
|
||||||
l.accept("+-")
|
|
||||||
l.acceptRun("0123456789")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it imaginary?
|
|
||||||
l.accept("i")
|
|
||||||
|
|
||||||
// Next thing mustn't be alphanumeric.
|
|
||||||
if isAlphaNumeric(l.peek()) {
|
|
||||||
l.next()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexIdentifier scans an ID
|
|
||||||
func lexIdentifier(l *Lexer) lexFunc {
|
|
||||||
str := l.findRegexp(rID)
|
|
||||||
if len(str) == 0 {
|
|
||||||
// this is rotten
|
|
||||||
panic("Identifier expected")
|
|
||||||
}
|
|
||||||
|
|
||||||
l.pos += len(str)
|
|
||||||
l.emit(TokenID)
|
|
||||||
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// lexPathLiteral scans an [ID]
|
|
||||||
func lexPathLiteral(l *Lexer) lexFunc {
|
|
||||||
for {
|
|
||||||
r := l.next()
|
|
||||||
if r == eof || r == '\n' {
|
|
||||||
return l.errorf("Unterminated path literal")
|
|
||||||
}
|
|
||||||
|
|
||||||
if r == ']' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
l.emit(TokenID)
|
|
||||||
|
|
||||||
return lexExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
// isIgnorable returns true if given character is ignorable (ie. whitespace of line feed)
|
|
||||||
func isIgnorable(r rune) bool {
|
|
||||||
return r == ' ' || r == '\t' || r == '\n'
|
|
||||||
}
|
|
||||||
|
|
||||||
// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore.
|
|
||||||
//
|
|
||||||
// NOTE borrowed from https://github.com/golang/go/tree/master/src/text/template/parse/lex.go
|
|
||||||
func isAlphaNumeric(r rune) bool {
|
|
||||||
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
|
|
||||||
}
|
|
183
vendor/github.com/aymerick/raymond/lexer/token.go
generated
vendored
183
vendor/github.com/aymerick/raymond/lexer/token.go
generated
vendored
@ -1,183 +0,0 @@
|
|||||||
package lexer
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TokenError represents an error
|
|
||||||
TokenError TokenKind = iota
|
|
||||||
|
|
||||||
// TokenEOF represents an End Of File
|
|
||||||
TokenEOF
|
|
||||||
|
|
||||||
//
|
|
||||||
// Mustache delimiters
|
|
||||||
//
|
|
||||||
|
|
||||||
// TokenOpen is the OPEN token
|
|
||||||
TokenOpen
|
|
||||||
|
|
||||||
// TokenClose is the CLOSE token
|
|
||||||
TokenClose
|
|
||||||
|
|
||||||
// TokenOpenRawBlock is the OPEN_RAW_BLOCK token
|
|
||||||
TokenOpenRawBlock
|
|
||||||
|
|
||||||
// TokenCloseRawBlock is the CLOSE_RAW_BLOCK token
|
|
||||||
TokenCloseRawBlock
|
|
||||||
|
|
||||||
// TokenOpenEndRawBlock is the END_RAW_BLOCK token
|
|
||||||
TokenOpenEndRawBlock
|
|
||||||
|
|
||||||
// TokenOpenUnescaped is the OPEN_UNESCAPED token
|
|
||||||
TokenOpenUnescaped
|
|
||||||
|
|
||||||
// TokenCloseUnescaped is the CLOSE_UNESCAPED token
|
|
||||||
TokenCloseUnescaped
|
|
||||||
|
|
||||||
// TokenOpenBlock is the OPEN_BLOCK token
|
|
||||||
TokenOpenBlock
|
|
||||||
|
|
||||||
// TokenOpenEndBlock is the OPEN_ENDBLOCK token
|
|
||||||
TokenOpenEndBlock
|
|
||||||
|
|
||||||
// TokenInverse is the INVERSE token
|
|
||||||
TokenInverse
|
|
||||||
|
|
||||||
// TokenOpenInverse is the OPEN_INVERSE token
|
|
||||||
TokenOpenInverse
|
|
||||||
|
|
||||||
// TokenOpenInverseChain is the OPEN_INVERSE_CHAIN token
|
|
||||||
TokenOpenInverseChain
|
|
||||||
|
|
||||||
// TokenOpenPartial is the OPEN_PARTIAL token
|
|
||||||
TokenOpenPartial
|
|
||||||
|
|
||||||
// TokenComment is the COMMENT token
|
|
||||||
TokenComment
|
|
||||||
|
|
||||||
//
|
|
||||||
// Inside mustaches
|
|
||||||
//
|
|
||||||
|
|
||||||
// TokenOpenSexpr is the OPEN_SEXPR token
|
|
||||||
TokenOpenSexpr
|
|
||||||
|
|
||||||
// TokenCloseSexpr is the CLOSE_SEXPR token
|
|
||||||
TokenCloseSexpr
|
|
||||||
|
|
||||||
// TokenEquals is the EQUALS token
|
|
||||||
TokenEquals
|
|
||||||
|
|
||||||
// TokenData is the DATA token
|
|
||||||
TokenData
|
|
||||||
|
|
||||||
// TokenSep is the SEP token
|
|
||||||
TokenSep
|
|
||||||
|
|
||||||
// TokenOpenBlockParams is the OPEN_BLOCK_PARAMS token
|
|
||||||
TokenOpenBlockParams
|
|
||||||
|
|
||||||
// TokenCloseBlockParams is the CLOSE_BLOCK_PARAMS token
|
|
||||||
TokenCloseBlockParams
|
|
||||||
|
|
||||||
//
|
|
||||||
// Tokens with content
|
|
||||||
//
|
|
||||||
|
|
||||||
// TokenContent is the CONTENT token
|
|
||||||
TokenContent
|
|
||||||
|
|
||||||
// TokenID is the ID token
|
|
||||||
TokenID
|
|
||||||
|
|
||||||
// TokenString is the STRING token
|
|
||||||
TokenString
|
|
||||||
|
|
||||||
// TokenNumber is the NUMBER token
|
|
||||||
TokenNumber
|
|
||||||
|
|
||||||
// TokenBoolean is the BOOLEAN token
|
|
||||||
TokenBoolean
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Option to generate token position in its string representation
|
|
||||||
dumpTokenPos = false
|
|
||||||
|
|
||||||
// Option to generate values for all token kinds for their string representations
|
|
||||||
dumpAllTokensVal = true
|
|
||||||
)
|
|
||||||
|
|
||||||
// TokenKind represents a Token type.
|
|
||||||
type TokenKind int
|
|
||||||
|
|
||||||
// Token represents a scanned token.
|
|
||||||
type Token struct {
|
|
||||||
Kind TokenKind // Token kind
|
|
||||||
Val string // Token value
|
|
||||||
|
|
||||||
Pos int // Byte position in input string
|
|
||||||
Line int // Line number in input string
|
|
||||||
}
|
|
||||||
|
|
||||||
// tokenName permits to display token name given token type
|
|
||||||
var tokenName = map[TokenKind]string{
|
|
||||||
TokenError: "Error",
|
|
||||||
TokenEOF: "EOF",
|
|
||||||
TokenContent: "Content",
|
|
||||||
TokenComment: "Comment",
|
|
||||||
TokenOpen: "Open",
|
|
||||||
TokenClose: "Close",
|
|
||||||
TokenOpenUnescaped: "OpenUnescaped",
|
|
||||||
TokenCloseUnescaped: "CloseUnescaped",
|
|
||||||
TokenOpenBlock: "OpenBlock",
|
|
||||||
TokenOpenEndBlock: "OpenEndBlock",
|
|
||||||
TokenOpenRawBlock: "OpenRawBlock",
|
|
||||||
TokenCloseRawBlock: "CloseRawBlock",
|
|
||||||
TokenOpenEndRawBlock: "OpenEndRawBlock",
|
|
||||||
TokenOpenBlockParams: "OpenBlockParams",
|
|
||||||
TokenCloseBlockParams: "CloseBlockParams",
|
|
||||||
TokenInverse: "Inverse",
|
|
||||||
TokenOpenInverse: "OpenInverse",
|
|
||||||
TokenOpenInverseChain: "OpenInverseChain",
|
|
||||||
TokenOpenPartial: "OpenPartial",
|
|
||||||
TokenOpenSexpr: "OpenSexpr",
|
|
||||||
TokenCloseSexpr: "CloseSexpr",
|
|
||||||
TokenID: "ID",
|
|
||||||
TokenEquals: "Equals",
|
|
||||||
TokenString: "String",
|
|
||||||
TokenNumber: "Number",
|
|
||||||
TokenBoolean: "Boolean",
|
|
||||||
TokenData: "Data",
|
|
||||||
TokenSep: "Sep",
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the token kind string representation for debugging.
|
|
||||||
func (k TokenKind) String() string {
|
|
||||||
s := tokenName[k]
|
|
||||||
if s == "" {
|
|
||||||
return fmt.Sprintf("Token-%d", int(k))
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the token string representation for debugging.
|
|
||||||
func (t Token) String() string {
|
|
||||||
result := ""
|
|
||||||
|
|
||||||
if dumpTokenPos {
|
|
||||||
result += fmt.Sprintf("%d:", t.Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
result += fmt.Sprintf("%s", t.Kind)
|
|
||||||
|
|
||||||
if (dumpAllTokensVal || (t.Kind >= TokenContent)) && len(t.Val) > 0 {
|
|
||||||
if len(t.Val) > 100 {
|
|
||||||
result += fmt.Sprintf("{%.20q...}", t.Val)
|
|
||||||
} else {
|
|
||||||
result += fmt.Sprintf("{%q}", t.Val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
846
vendor/github.com/aymerick/raymond/parser/parser.go
generated
vendored
846
vendor/github.com/aymerick/raymond/parser/parser.go
generated
vendored
@ -1,846 +0,0 @@
|
|||||||
// Package parser provides a handlebars syntax analyser. It consumes the tokens provided by the lexer to build an AST.
|
|
||||||
package parser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/aymerick/raymond/ast"
|
|
||||||
"github.com/aymerick/raymond/lexer"
|
|
||||||
)
|
|
||||||
|
|
||||||
// References:
|
|
||||||
// - https://github.com/wycats/handlebars.js/blob/master/src/handlebars.yy
|
|
||||||
// - https://github.com/golang/go/blob/master/src/text/template/parse/parse.go
|
|
||||||
|
|
||||||
// parser is a syntax analyzer.
|
|
||||||
type parser struct {
|
|
||||||
// Lexer
|
|
||||||
lex *lexer.Lexer
|
|
||||||
|
|
||||||
// Root node
|
|
||||||
root ast.Node
|
|
||||||
|
|
||||||
// Tokens parsed but not consumed yet
|
|
||||||
tokens []*lexer.Token
|
|
||||||
|
|
||||||
// All tokens have been retreieved from lexer
|
|
||||||
lexOver bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
rOpenComment = regexp.MustCompile(`^\{\{~?!-?-?`)
|
|
||||||
rCloseComment = regexp.MustCompile(`-?-?~?\}\}$`)
|
|
||||||
rOpenAmp = regexp.MustCompile(`^\{\{~?&`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// new instanciates a new parser
|
|
||||||
func new(input string) *parser {
|
|
||||||
return &parser{
|
|
||||||
lex: lexer.Scan(input),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse analyzes given input and returns the AST root node.
|
|
||||||
func Parse(input string) (result *ast.Program, err error) {
|
|
||||||
// recover error
|
|
||||||
defer errRecover(&err)
|
|
||||||
|
|
||||||
parser := new(input)
|
|
||||||
|
|
||||||
// parse
|
|
||||||
result = parser.parseProgram()
|
|
||||||
|
|
||||||
// check last token
|
|
||||||
token := parser.shift()
|
|
||||||
if token.Kind != lexer.TokenEOF {
|
|
||||||
// Parsing ended before EOF
|
|
||||||
errToken(token, "Syntax error")
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix whitespaces
|
|
||||||
processWhitespaces(result)
|
|
||||||
|
|
||||||
// named returned values
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// errRecover recovers parsing panic
|
|
||||||
func errRecover(errp *error) {
|
|
||||||
e := recover()
|
|
||||||
if e != nil {
|
|
||||||
switch err := e.(type) {
|
|
||||||
case runtime.Error:
|
|
||||||
panic(e)
|
|
||||||
case error:
|
|
||||||
*errp = err
|
|
||||||
default:
|
|
||||||
panic(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// errPanic panics
|
|
||||||
func errPanic(err error, line int) {
|
|
||||||
panic(fmt.Errorf("Parse error on line %d:\n%s", line, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// errNode panics with given node infos
|
|
||||||
func errNode(node ast.Node, msg string) {
|
|
||||||
errPanic(fmt.Errorf("%s\nNode: %s", msg, node), node.Location().Line)
|
|
||||||
}
|
|
||||||
|
|
||||||
// errNode panics with given Token infos
|
|
||||||
func errToken(tok *lexer.Token, msg string) {
|
|
||||||
errPanic(fmt.Errorf("%s\nToken: %s", msg, tok), tok.Line)
|
|
||||||
}
|
|
||||||
|
|
||||||
// errNode panics because of an unexpected Token kind
|
|
||||||
func errExpected(expect lexer.TokenKind, tok *lexer.Token) {
|
|
||||||
errPanic(fmt.Errorf("Expecting %s, got: '%s'", expect, tok), tok.Line)
|
|
||||||
}
|
|
||||||
|
|
||||||
// program : statement*
|
|
||||||
func (p *parser) parseProgram() *ast.Program {
|
|
||||||
result := ast.NewProgram(p.next().Pos, p.next().Line)
|
|
||||||
|
|
||||||
for p.isStatement() {
|
|
||||||
result.AddStatement(p.parseStatement())
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// statement : mustache | block | rawBlock | partial | content | COMMENT
|
|
||||||
func (p *parser) parseStatement() ast.Node {
|
|
||||||
var result ast.Node
|
|
||||||
|
|
||||||
tok := p.next()
|
|
||||||
|
|
||||||
switch tok.Kind {
|
|
||||||
case lexer.TokenOpen, lexer.TokenOpenUnescaped:
|
|
||||||
// mustache
|
|
||||||
result = p.parseMustache()
|
|
||||||
case lexer.TokenOpenBlock:
|
|
||||||
// block
|
|
||||||
result = p.parseBlock()
|
|
||||||
case lexer.TokenOpenInverse:
|
|
||||||
// block
|
|
||||||
result = p.parseInverse()
|
|
||||||
case lexer.TokenOpenRawBlock:
|
|
||||||
// rawBlock
|
|
||||||
result = p.parseRawBlock()
|
|
||||||
case lexer.TokenOpenPartial:
|
|
||||||
// partial
|
|
||||||
result = p.parsePartial()
|
|
||||||
case lexer.TokenContent:
|
|
||||||
// content
|
|
||||||
result = p.parseContent()
|
|
||||||
case lexer.TokenComment:
|
|
||||||
// COMMENT
|
|
||||||
result = p.parseComment()
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// isStatement returns true if next token starts a statement
|
|
||||||
func (p *parser) isStatement() bool {
|
|
||||||
if !p.have(1) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch p.next().Kind {
|
|
||||||
case lexer.TokenOpen, lexer.TokenOpenUnescaped, lexer.TokenOpenBlock,
|
|
||||||
lexer.TokenOpenInverse, lexer.TokenOpenRawBlock, lexer.TokenOpenPartial,
|
|
||||||
lexer.TokenContent, lexer.TokenComment:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// content : CONTENT
|
|
||||||
func (p *parser) parseContent() *ast.ContentStatement {
|
|
||||||
// CONTENT
|
|
||||||
tok := p.shift()
|
|
||||||
if tok.Kind != lexer.TokenContent {
|
|
||||||
// @todo This check can be removed if content is optional in a raw block
|
|
||||||
errExpected(lexer.TokenContent, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ast.NewContentStatement(tok.Pos, tok.Line, tok.Val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// COMMENT
|
|
||||||
func (p *parser) parseComment() *ast.CommentStatement {
|
|
||||||
// COMMENT
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
value := rOpenComment.ReplaceAllString(tok.Val, "")
|
|
||||||
value = rCloseComment.ReplaceAllString(value, "")
|
|
||||||
|
|
||||||
result := ast.NewCommentStatement(tok.Pos, tok.Line, value)
|
|
||||||
result.Strip = ast.NewStripForStr(tok.Val)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// param* hash?
|
|
||||||
func (p *parser) parseExpressionParamsHash() ([]ast.Node, *ast.Hash) {
|
|
||||||
var params []ast.Node
|
|
||||||
var hash *ast.Hash
|
|
||||||
|
|
||||||
// params*
|
|
||||||
if p.isParam() {
|
|
||||||
params = p.parseParams()
|
|
||||||
}
|
|
||||||
|
|
||||||
// hash?
|
|
||||||
if p.isHashSegment() {
|
|
||||||
hash = p.parseHash()
|
|
||||||
}
|
|
||||||
|
|
||||||
return params, hash
|
|
||||||
}
|
|
||||||
|
|
||||||
// helperName param* hash?
|
|
||||||
func (p *parser) parseExpression(tok *lexer.Token) *ast.Expression {
|
|
||||||
result := ast.NewExpression(tok.Pos, tok.Line)
|
|
||||||
|
|
||||||
// helperName
|
|
||||||
result.Path = p.parseHelperName()
|
|
||||||
|
|
||||||
// param* hash?
|
|
||||||
result.Params, result.Hash = p.parseExpressionParamsHash()
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// rawBlock : openRawBlock content endRawBlock
|
|
||||||
// openRawBlock : OPEN_RAW_BLOCK helperName param* hash? CLOSE_RAW_BLOCK
|
|
||||||
// endRawBlock : OPEN_END_RAW_BLOCK helperName CLOSE_RAW_BLOCK
|
|
||||||
func (p *parser) parseRawBlock() *ast.BlockStatement {
|
|
||||||
// OPEN_RAW_BLOCK
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
result := ast.NewBlockStatement(tok.Pos, tok.Line)
|
|
||||||
|
|
||||||
// helperName param* hash?
|
|
||||||
result.Expression = p.parseExpression(tok)
|
|
||||||
|
|
||||||
openName := result.Expression.Canonical()
|
|
||||||
|
|
||||||
// CLOSE_RAW_BLOCK
|
|
||||||
tok = p.shift()
|
|
||||||
if tok.Kind != lexer.TokenCloseRawBlock {
|
|
||||||
errExpected(lexer.TokenCloseRawBlock, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
// content
|
|
||||||
// @todo Is content mandatory in a raw block ?
|
|
||||||
content := p.parseContent()
|
|
||||||
|
|
||||||
program := ast.NewProgram(tok.Pos, tok.Line)
|
|
||||||
program.AddStatement(content)
|
|
||||||
|
|
||||||
result.Program = program
|
|
||||||
|
|
||||||
// OPEN_END_RAW_BLOCK
|
|
||||||
tok = p.shift()
|
|
||||||
if tok.Kind != lexer.TokenOpenEndRawBlock {
|
|
||||||
// should never happen as it is caught by lexer
|
|
||||||
errExpected(lexer.TokenOpenEndRawBlock, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
// helperName
|
|
||||||
endID := p.parseHelperName()
|
|
||||||
|
|
||||||
closeName, ok := ast.HelperNameStr(endID)
|
|
||||||
if !ok {
|
|
||||||
errNode(endID, "Erroneous closing expression")
|
|
||||||
}
|
|
||||||
|
|
||||||
if openName != closeName {
|
|
||||||
errNode(endID, fmt.Sprintf("%s doesn't match %s", openName, closeName))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CLOSE_RAW_BLOCK
|
|
||||||
tok = p.shift()
|
|
||||||
if tok.Kind != lexer.TokenCloseRawBlock {
|
|
||||||
errExpected(lexer.TokenCloseRawBlock, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// block : openBlock program inverseChain? closeBlock
|
|
||||||
func (p *parser) parseBlock() *ast.BlockStatement {
|
|
||||||
// openBlock
|
|
||||||
result, blockParams := p.parseOpenBlock()
|
|
||||||
|
|
||||||
// program
|
|
||||||
program := p.parseProgram()
|
|
||||||
program.BlockParams = blockParams
|
|
||||||
result.Program = program
|
|
||||||
|
|
||||||
// inverseChain?
|
|
||||||
if p.isInverseChain() {
|
|
||||||
result.Inverse = p.parseInverseChain()
|
|
||||||
}
|
|
||||||
|
|
||||||
// closeBlock
|
|
||||||
p.parseCloseBlock(result)
|
|
||||||
|
|
||||||
setBlockInverseStrip(result)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// setBlockInverseStrip is called when parsing `block` (openBlock | openInverse) and `inverseChain`
|
|
||||||
//
|
|
||||||
// TODO: This was totally cargo culted ! CHECK THAT !
|
|
||||||
//
|
|
||||||
// cf. prepareBlock() in:
|
|
||||||
// https://github.com/wycats/handlebars.js/blob/master/lib/handlebars/compiler/helper.js
|
|
||||||
func setBlockInverseStrip(block *ast.BlockStatement) {
|
|
||||||
if block.Inverse == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if block.Inverse.Chained {
|
|
||||||
b, _ := block.Inverse.Body[0].(*ast.BlockStatement)
|
|
||||||
b.CloseStrip = block.CloseStrip
|
|
||||||
}
|
|
||||||
|
|
||||||
block.InverseStrip = block.Inverse.Strip
|
|
||||||
}
|
|
||||||
|
|
||||||
// block : openInverse program inverseAndProgram? closeBlock
|
|
||||||
func (p *parser) parseInverse() *ast.BlockStatement {
|
|
||||||
// openInverse
|
|
||||||
result, blockParams := p.parseOpenBlock()
|
|
||||||
|
|
||||||
// program
|
|
||||||
program := p.parseProgram()
|
|
||||||
|
|
||||||
program.BlockParams = blockParams
|
|
||||||
result.Inverse = program
|
|
||||||
|
|
||||||
// inverseAndProgram?
|
|
||||||
if p.isInverse() {
|
|
||||||
result.Program = p.parseInverseAndProgram()
|
|
||||||
}
|
|
||||||
|
|
||||||
// closeBlock
|
|
||||||
p.parseCloseBlock(result)
|
|
||||||
|
|
||||||
setBlockInverseStrip(result)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// helperName param* hash? blockParams?
|
|
||||||
func (p *parser) parseOpenBlockExpression(tok *lexer.Token) (*ast.BlockStatement, []string) {
|
|
||||||
var blockParams []string
|
|
||||||
|
|
||||||
result := ast.NewBlockStatement(tok.Pos, tok.Line)
|
|
||||||
|
|
||||||
// helperName param* hash?
|
|
||||||
result.Expression = p.parseExpression(tok)
|
|
||||||
|
|
||||||
// blockParams?
|
|
||||||
if p.isBlockParams() {
|
|
||||||
blockParams = p.parseBlockParams()
|
|
||||||
}
|
|
||||||
|
|
||||||
// named returned values
|
|
||||||
return result, blockParams
|
|
||||||
}
|
|
||||||
|
|
||||||
// inverseChain : openInverseChain program inverseChain?
|
|
||||||
// | inverseAndProgram
|
|
||||||
func (p *parser) parseInverseChain() *ast.Program {
|
|
||||||
if p.isInverse() {
|
|
||||||
// inverseAndProgram
|
|
||||||
return p.parseInverseAndProgram()
|
|
||||||
}
|
|
||||||
|
|
||||||
result := ast.NewProgram(p.next().Pos, p.next().Line)
|
|
||||||
|
|
||||||
// openInverseChain
|
|
||||||
block, blockParams := p.parseOpenBlock()
|
|
||||||
|
|
||||||
// program
|
|
||||||
program := p.parseProgram()
|
|
||||||
|
|
||||||
program.BlockParams = blockParams
|
|
||||||
block.Program = program
|
|
||||||
|
|
||||||
// inverseChain?
|
|
||||||
if p.isInverseChain() {
|
|
||||||
block.Inverse = p.parseInverseChain()
|
|
||||||
}
|
|
||||||
|
|
||||||
setBlockInverseStrip(block)
|
|
||||||
|
|
||||||
result.Chained = true
|
|
||||||
result.AddStatement(block)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if current token starts an inverse chain
|
|
||||||
func (p *parser) isInverseChain() bool {
|
|
||||||
return p.isOpenInverseChain() || p.isInverse()
|
|
||||||
}
|
|
||||||
|
|
||||||
// inverseAndProgram : INVERSE program
|
|
||||||
func (p *parser) parseInverseAndProgram() *ast.Program {
|
|
||||||
// INVERSE
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
// program
|
|
||||||
result := p.parseProgram()
|
|
||||||
result.Strip = ast.NewStripForStr(tok.Val)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// openBlock : OPEN_BLOCK helperName param* hash? blockParams? CLOSE
|
|
||||||
// openInverse : OPEN_INVERSE helperName param* hash? blockParams? CLOSE
|
|
||||||
// openInverseChain: OPEN_INVERSE_CHAIN helperName param* hash? blockParams? CLOSE
|
|
||||||
func (p *parser) parseOpenBlock() (*ast.BlockStatement, []string) {
|
|
||||||
// OPEN_BLOCK | OPEN_INVERSE | OPEN_INVERSE_CHAIN
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
// helperName param* hash? blockParams?
|
|
||||||
result, blockParams := p.parseOpenBlockExpression(tok)
|
|
||||||
|
|
||||||
// CLOSE
|
|
||||||
tokClose := p.shift()
|
|
||||||
if tokClose.Kind != lexer.TokenClose {
|
|
||||||
errExpected(lexer.TokenClose, tokClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.OpenStrip = ast.NewStrip(tok.Val, tokClose.Val)
|
|
||||||
|
|
||||||
// named returned values
|
|
||||||
return result, blockParams
|
|
||||||
}
|
|
||||||
|
|
||||||
// closeBlock : OPEN_ENDBLOCK helperName CLOSE
|
|
||||||
func (p *parser) parseCloseBlock(block *ast.BlockStatement) {
|
|
||||||
// OPEN_ENDBLOCK
|
|
||||||
tok := p.shift()
|
|
||||||
if tok.Kind != lexer.TokenOpenEndBlock {
|
|
||||||
errExpected(lexer.TokenOpenEndBlock, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
// helperName
|
|
||||||
endID := p.parseHelperName()
|
|
||||||
|
|
||||||
closeName, ok := ast.HelperNameStr(endID)
|
|
||||||
if !ok {
|
|
||||||
errNode(endID, "Erroneous closing expression")
|
|
||||||
}
|
|
||||||
|
|
||||||
openName := block.Expression.Canonical()
|
|
||||||
if openName != closeName {
|
|
||||||
errNode(endID, fmt.Sprintf("%s doesn't match %s", openName, closeName))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CLOSE
|
|
||||||
tokClose := p.shift()
|
|
||||||
if tokClose.Kind != lexer.TokenClose {
|
|
||||||
errExpected(lexer.TokenClose, tokClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
block.CloseStrip = ast.NewStrip(tok.Val, tokClose.Val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mustache : OPEN helperName param* hash? CLOSE
|
|
||||||
// | OPEN_UNESCAPED helperName param* hash? CLOSE_UNESCAPED
|
|
||||||
func (p *parser) parseMustache() *ast.MustacheStatement {
|
|
||||||
// OPEN | OPEN_UNESCAPED
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
closeToken := lexer.TokenClose
|
|
||||||
if tok.Kind == lexer.TokenOpenUnescaped {
|
|
||||||
closeToken = lexer.TokenCloseUnescaped
|
|
||||||
}
|
|
||||||
|
|
||||||
unescaped := false
|
|
||||||
if (tok.Kind == lexer.TokenOpenUnescaped) || (rOpenAmp.MatchString(tok.Val)) {
|
|
||||||
unescaped = true
|
|
||||||
}
|
|
||||||
|
|
||||||
result := ast.NewMustacheStatement(tok.Pos, tok.Line, unescaped)
|
|
||||||
|
|
||||||
// helperName param* hash?
|
|
||||||
result.Expression = p.parseExpression(tok)
|
|
||||||
|
|
||||||
// CLOSE | CLOSE_UNESCAPED
|
|
||||||
tokClose := p.shift()
|
|
||||||
if tokClose.Kind != closeToken {
|
|
||||||
errExpected(closeToken, tokClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Strip = ast.NewStrip(tok.Val, tokClose.Val)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// partial : OPEN_PARTIAL partialName param* hash? CLOSE
|
|
||||||
func (p *parser) parsePartial() *ast.PartialStatement {
|
|
||||||
// OPEN_PARTIAL
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
result := ast.NewPartialStatement(tok.Pos, tok.Line)
|
|
||||||
|
|
||||||
// partialName
|
|
||||||
result.Name = p.parsePartialName()
|
|
||||||
|
|
||||||
// param* hash?
|
|
||||||
result.Params, result.Hash = p.parseExpressionParamsHash()
|
|
||||||
|
|
||||||
// CLOSE
|
|
||||||
tokClose := p.shift()
|
|
||||||
if tokClose.Kind != lexer.TokenClose {
|
|
||||||
errExpected(lexer.TokenClose, tokClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Strip = ast.NewStrip(tok.Val, tokClose.Val)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// helperName | sexpr
|
|
||||||
func (p *parser) parseHelperNameOrSexpr() ast.Node {
|
|
||||||
if p.isSexpr() {
|
|
||||||
// sexpr
|
|
||||||
return p.parseSexpr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// helperName
|
|
||||||
return p.parseHelperName()
|
|
||||||
}
|
|
||||||
|
|
||||||
// param : helperName | sexpr
|
|
||||||
func (p *parser) parseParam() ast.Node {
|
|
||||||
return p.parseHelperNameOrSexpr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if next tokens represent a `param`
|
|
||||||
func (p *parser) isParam() bool {
|
|
||||||
return (p.isSexpr() || p.isHelperName()) && !p.isHashSegment()
|
|
||||||
}
|
|
||||||
|
|
||||||
// param*
|
|
||||||
func (p *parser) parseParams() []ast.Node {
|
|
||||||
var result []ast.Node
|
|
||||||
|
|
||||||
for p.isParam() {
|
|
||||||
result = append(result, p.parseParam())
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// sexpr : OPEN_SEXPR helperName param* hash? CLOSE_SEXPR
|
|
||||||
func (p *parser) parseSexpr() *ast.SubExpression {
|
|
||||||
// OPEN_SEXPR
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
result := ast.NewSubExpression(tok.Pos, tok.Line)
|
|
||||||
|
|
||||||
// helperName param* hash?
|
|
||||||
result.Expression = p.parseExpression(tok)
|
|
||||||
|
|
||||||
// CLOSE_SEXPR
|
|
||||||
tok = p.shift()
|
|
||||||
if tok.Kind != lexer.TokenCloseSexpr {
|
|
||||||
errExpected(lexer.TokenCloseSexpr, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// hash : hashSegment+
|
|
||||||
func (p *parser) parseHash() *ast.Hash {
|
|
||||||
var pairs []*ast.HashPair
|
|
||||||
|
|
||||||
for p.isHashSegment() {
|
|
||||||
pairs = append(pairs, p.parseHashSegment())
|
|
||||||
}
|
|
||||||
|
|
||||||
firstLoc := pairs[0].Location()
|
|
||||||
|
|
||||||
result := ast.NewHash(firstLoc.Pos, firstLoc.Line)
|
|
||||||
result.Pairs = pairs
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if next tokens represents a `hashSegment`
|
|
||||||
func (p *parser) isHashSegment() bool {
|
|
||||||
return p.have(2) && (p.next().Kind == lexer.TokenID) && (p.nextAt(1).Kind == lexer.TokenEquals)
|
|
||||||
}
|
|
||||||
|
|
||||||
// hashSegment : ID EQUALS param
|
|
||||||
func (p *parser) parseHashSegment() *ast.HashPair {
|
|
||||||
// ID
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
// EQUALS
|
|
||||||
p.shift()
|
|
||||||
|
|
||||||
// param
|
|
||||||
param := p.parseParam()
|
|
||||||
|
|
||||||
result := ast.NewHashPair(tok.Pos, tok.Line)
|
|
||||||
result.Key = tok.Val
|
|
||||||
result.Val = param
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// blockParams : OPEN_BLOCK_PARAMS ID+ CLOSE_BLOCK_PARAMS
|
|
||||||
func (p *parser) parseBlockParams() []string {
|
|
||||||
var result []string
|
|
||||||
|
|
||||||
// OPEN_BLOCK_PARAMS
|
|
||||||
tok := p.shift()
|
|
||||||
|
|
||||||
// ID+
|
|
||||||
for p.isID() {
|
|
||||||
result = append(result, p.shift().Val)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(result) == 0 {
|
|
||||||
errExpected(lexer.TokenID, p.next())
|
|
||||||
}
|
|
||||||
|
|
||||||
// CLOSE_BLOCK_PARAMS
|
|
||||||
tok = p.shift()
|
|
||||||
if tok.Kind != lexer.TokenCloseBlockParams {
|
|
||||||
errExpected(lexer.TokenCloseBlockParams, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// helperName : path | dataName | STRING | NUMBER | BOOLEAN | UNDEFINED | NULL
|
|
||||||
func (p *parser) parseHelperName() ast.Node {
|
|
||||||
var result ast.Node
|
|
||||||
|
|
||||||
tok := p.next()
|
|
||||||
|
|
||||||
switch tok.Kind {
|
|
||||||
case lexer.TokenBoolean:
|
|
||||||
// BOOLEAN
|
|
||||||
p.shift()
|
|
||||||
result = ast.NewBooleanLiteral(tok.Pos, tok.Line, (tok.Val == "true"), tok.Val)
|
|
||||||
case lexer.TokenNumber:
|
|
||||||
// NUMBER
|
|
||||||
p.shift()
|
|
||||||
|
|
||||||
val, isInt := parseNumber(tok)
|
|
||||||
result = ast.NewNumberLiteral(tok.Pos, tok.Line, val, isInt, tok.Val)
|
|
||||||
case lexer.TokenString:
|
|
||||||
// STRING
|
|
||||||
p.shift()
|
|
||||||
result = ast.NewStringLiteral(tok.Pos, tok.Line, tok.Val)
|
|
||||||
case lexer.TokenData:
|
|
||||||
// dataName
|
|
||||||
result = p.parseDataName()
|
|
||||||
default:
|
|
||||||
// path
|
|
||||||
result = p.parsePath(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseNumber parses a number
|
|
||||||
func parseNumber(tok *lexer.Token) (result float64, isInt bool) {
|
|
||||||
var valInt int
|
|
||||||
var err error
|
|
||||||
|
|
||||||
valInt, err = strconv.Atoi(tok.Val)
|
|
||||||
if err == nil {
|
|
||||||
isInt = true
|
|
||||||
|
|
||||||
result = float64(valInt)
|
|
||||||
} else {
|
|
||||||
isInt = false
|
|
||||||
|
|
||||||
result, err = strconv.ParseFloat(tok.Val, 64)
|
|
||||||
if err != nil {
|
|
||||||
errToken(tok, fmt.Sprintf("Failed to parse number: %s", tok.Val))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// named returned values
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if next tokens represent a `helperName`
|
|
||||||
func (p *parser) isHelperName() bool {
|
|
||||||
switch p.next().Kind {
|
|
||||||
case lexer.TokenBoolean, lexer.TokenNumber, lexer.TokenString, lexer.TokenData, lexer.TokenID:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// partialName : helperName | sexpr
|
|
||||||
func (p *parser) parsePartialName() ast.Node {
|
|
||||||
return p.parseHelperNameOrSexpr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// dataName : DATA pathSegments
|
|
||||||
func (p *parser) parseDataName() *ast.PathExpression {
|
|
||||||
// DATA
|
|
||||||
p.shift()
|
|
||||||
|
|
||||||
// pathSegments
|
|
||||||
return p.parsePath(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// path : pathSegments
|
|
||||||
// pathSegments : pathSegments SEP ID
|
|
||||||
// | ID
|
|
||||||
func (p *parser) parsePath(data bool) *ast.PathExpression {
|
|
||||||
var tok *lexer.Token
|
|
||||||
|
|
||||||
// ID
|
|
||||||
tok = p.shift()
|
|
||||||
if tok.Kind != lexer.TokenID {
|
|
||||||
errExpected(lexer.TokenID, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := ast.NewPathExpression(tok.Pos, tok.Line, data)
|
|
||||||
result.Part(tok.Val)
|
|
||||||
|
|
||||||
for p.isPathSep() {
|
|
||||||
// SEP
|
|
||||||
tok = p.shift()
|
|
||||||
result.Sep(tok.Val)
|
|
||||||
|
|
||||||
// ID
|
|
||||||
tok = p.shift()
|
|
||||||
if tok.Kind != lexer.TokenID {
|
|
||||||
errExpected(lexer.TokenID, tok)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Part(tok.Val)
|
|
||||||
|
|
||||||
if len(result.Parts) > 0 {
|
|
||||||
switch tok.Val {
|
|
||||||
case "..", ".", "this":
|
|
||||||
errToken(tok, "Invalid path: "+result.Original)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures there is token to parse at given index
|
|
||||||
func (p *parser) ensure(index int) {
|
|
||||||
if p.lexOver {
|
|
||||||
// nothing more to grab
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nb := index + 1
|
|
||||||
|
|
||||||
for len(p.tokens) < nb {
|
|
||||||
// fetch next token
|
|
||||||
tok := p.lex.NextToken()
|
|
||||||
|
|
||||||
// queue it
|
|
||||||
p.tokens = append(p.tokens, &tok)
|
|
||||||
|
|
||||||
if (tok.Kind == lexer.TokenEOF) || (tok.Kind == lexer.TokenError) {
|
|
||||||
p.lexOver = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// have returns true is there are a list given number of tokens to consume left
|
|
||||||
func (p *parser) have(nb int) bool {
|
|
||||||
p.ensure(nb - 1)
|
|
||||||
|
|
||||||
return len(p.tokens) >= nb
|
|
||||||
}
|
|
||||||
|
|
||||||
// nextAt returns next token at given index, without consuming it
|
|
||||||
func (p *parser) nextAt(index int) *lexer.Token {
|
|
||||||
p.ensure(index)
|
|
||||||
|
|
||||||
return p.tokens[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
// next returns next token without consuming it
|
|
||||||
func (p *parser) next() *lexer.Token {
|
|
||||||
return p.nextAt(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// shift returns next token and remove it from the tokens buffer
|
|
||||||
//
|
|
||||||
// Panics if next token is `TokenError`
|
|
||||||
func (p *parser) shift() *lexer.Token {
|
|
||||||
var result *lexer.Token
|
|
||||||
|
|
||||||
p.ensure(0)
|
|
||||||
|
|
||||||
result, p.tokens = p.tokens[0], p.tokens[1:]
|
|
||||||
|
|
||||||
// check error token
|
|
||||||
if result.Kind == lexer.TokenError {
|
|
||||||
errToken(result, "Lexer error")
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// isToken returns true if next token is of given type
|
|
||||||
func (p *parser) isToken(kind lexer.TokenKind) bool {
|
|
||||||
return p.have(1) && p.next().Kind == kind
|
|
||||||
}
|
|
||||||
|
|
||||||
// isSexpr returns true if next token starts a sexpr
|
|
||||||
func (p *parser) isSexpr() bool {
|
|
||||||
return p.isToken(lexer.TokenOpenSexpr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isPathSep returns true if next token is a path separator
|
|
||||||
func (p *parser) isPathSep() bool {
|
|
||||||
return p.isToken(lexer.TokenSep)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isID returns true if next token is an ID
|
|
||||||
func (p *parser) isID() bool {
|
|
||||||
return p.isToken(lexer.TokenID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isBlockParams returns true if next token starts a block params
|
|
||||||
func (p *parser) isBlockParams() bool {
|
|
||||||
return p.isToken(lexer.TokenOpenBlockParams)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isInverse returns true if next token starts an INVERSE sequence
|
|
||||||
func (p *parser) isInverse() bool {
|
|
||||||
return p.isToken(lexer.TokenInverse)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isOpenInverseChain returns true if next token is OPEN_INVERSE_CHAIN
|
|
||||||
func (p *parser) isOpenInverseChain() bool {
|
|
||||||
return p.isToken(lexer.TokenOpenInverseChain)
|
|
||||||
}
|
|
360
vendor/github.com/aymerick/raymond/parser/whitespace.go
generated
vendored
360
vendor/github.com/aymerick/raymond/parser/whitespace.go
generated
vendored
@ -1,360 +0,0 @@
|
|||||||
package parser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
"github.com/aymerick/raymond/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
// whitespaceVisitor walks through the AST to perform whitespace control
|
|
||||||
//
|
|
||||||
// The logic was shamelessly borrowed from:
|
|
||||||
// https://github.com/wycats/handlebars.js/blob/master/lib/handlebars/compiler/whitespace-control.js
|
|
||||||
type whitespaceVisitor struct {
|
|
||||||
isRootSeen bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
rTrimLeft = regexp.MustCompile(`^[ \t]*\r?\n?`)
|
|
||||||
rTrimLeftMultiple = regexp.MustCompile(`^\s+`)
|
|
||||||
|
|
||||||
rTrimRight = regexp.MustCompile(`[ \t]+$`)
|
|
||||||
rTrimRightMultiple = regexp.MustCompile(`\s+$`)
|
|
||||||
|
|
||||||
rPrevWhitespace = regexp.MustCompile(`\r?\n\s*?$`)
|
|
||||||
rPrevWhitespaceStart = regexp.MustCompile(`(^|\r?\n)\s*?$`)
|
|
||||||
|
|
||||||
rNextWhitespace = regexp.MustCompile(`^\s*?\r?\n`)
|
|
||||||
rNextWhitespaceEnd = regexp.MustCompile(`^\s*?(\r?\n|$)`)
|
|
||||||
|
|
||||||
rPartialIndent = regexp.MustCompile(`([ \t]+$)`)
|
|
||||||
)
|
|
||||||
|
|
||||||
// newWhitespaceVisitor instanciates a new whitespaceVisitor
|
|
||||||
func newWhitespaceVisitor() *whitespaceVisitor {
|
|
||||||
return &whitespaceVisitor{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// processWhitespaces performs whitespace control on given AST
|
|
||||||
//
|
|
||||||
// WARNING: It must be called only once on AST.
|
|
||||||
func processWhitespaces(node ast.Node) {
|
|
||||||
node.Accept(newWhitespaceVisitor())
|
|
||||||
}
|
|
||||||
|
|
||||||
func omitRightFirst(body []ast.Node, multiple bool) {
|
|
||||||
omitRight(body, -1, multiple)
|
|
||||||
}
|
|
||||||
|
|
||||||
func omitRight(body []ast.Node, i int, multiple bool) {
|
|
||||||
if i+1 >= len(body) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
current := body[i+1]
|
|
||||||
|
|
||||||
node, ok := current.(*ast.ContentStatement)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !multiple && node.RightStripped {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
original := node.Value
|
|
||||||
|
|
||||||
r := rTrimLeft
|
|
||||||
if multiple {
|
|
||||||
r = rTrimLeftMultiple
|
|
||||||
}
|
|
||||||
|
|
||||||
node.Value = r.ReplaceAllString(node.Value, "")
|
|
||||||
|
|
||||||
node.RightStripped = (original != node.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func omitLeftLast(body []ast.Node, multiple bool) {
|
|
||||||
omitLeft(body, len(body), multiple)
|
|
||||||
}
|
|
||||||
|
|
||||||
func omitLeft(body []ast.Node, i int, multiple bool) bool {
|
|
||||||
if i-1 < 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
current := body[i-1]
|
|
||||||
|
|
||||||
node, ok := current.(*ast.ContentStatement)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !multiple && node.LeftStripped {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
original := node.Value
|
|
||||||
|
|
||||||
r := rTrimRight
|
|
||||||
if multiple {
|
|
||||||
r = rTrimRightMultiple
|
|
||||||
}
|
|
||||||
|
|
||||||
node.Value = r.ReplaceAllString(node.Value, "")
|
|
||||||
|
|
||||||
node.LeftStripped = (original != node.Value)
|
|
||||||
|
|
||||||
return node.LeftStripped
|
|
||||||
}
|
|
||||||
|
|
||||||
func isPrevWhitespace(body []ast.Node) bool {
|
|
||||||
return isPrevWhitespaceProgram(body, len(body), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isPrevWhitespaceProgram(body []ast.Node, i int, isRoot bool) bool {
|
|
||||||
if i < 1 {
|
|
||||||
return isRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
prev := body[i-1]
|
|
||||||
|
|
||||||
if node, ok := prev.(*ast.ContentStatement); ok {
|
|
||||||
if (node.Value == "") && node.RightStripped {
|
|
||||||
// already stripped, so it may be an empty string not catched by regexp
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
r := rPrevWhitespaceStart
|
|
||||||
if (i > 1) || !isRoot {
|
|
||||||
r = rPrevWhitespace
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.MatchString(node.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNextWhitespace(body []ast.Node) bool {
|
|
||||||
return isNextWhitespaceProgram(body, -1, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNextWhitespaceProgram(body []ast.Node, i int, isRoot bool) bool {
|
|
||||||
if i+1 >= len(body) {
|
|
||||||
return isRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
next := body[i+1]
|
|
||||||
|
|
||||||
if node, ok := next.(*ast.ContentStatement); ok {
|
|
||||||
if (node.Value == "") && node.LeftStripped {
|
|
||||||
// already stripped, so it may be an empty string not catched by regexp
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
r := rNextWhitespaceEnd
|
|
||||||
if (i+2 > len(body)) || !isRoot {
|
|
||||||
r = rNextWhitespace
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.MatchString(node.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Visitor interface
|
|
||||||
//
|
|
||||||
|
|
||||||
func (v *whitespaceVisitor) VisitProgram(program *ast.Program) interface{} {
|
|
||||||
isRoot := !v.isRootSeen
|
|
||||||
v.isRootSeen = true
|
|
||||||
|
|
||||||
body := program.Body
|
|
||||||
for i, current := range body {
|
|
||||||
strip, _ := current.Accept(v).(*ast.Strip)
|
|
||||||
if strip == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_isPrevWhitespace := isPrevWhitespaceProgram(body, i, isRoot)
|
|
||||||
_isNextWhitespace := isNextWhitespaceProgram(body, i, isRoot)
|
|
||||||
|
|
||||||
openStandalone := strip.OpenStandalone && _isPrevWhitespace
|
|
||||||
closeStandalone := strip.CloseStandalone && _isNextWhitespace
|
|
||||||
inlineStandalone := strip.InlineStandalone && _isPrevWhitespace && _isNextWhitespace
|
|
||||||
|
|
||||||
if strip.Close {
|
|
||||||
omitRight(body, i, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if strip.Open && (i > 0) {
|
|
||||||
omitLeft(body, i, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if inlineStandalone {
|
|
||||||
omitRight(body, i, false)
|
|
||||||
|
|
||||||
if omitLeft(body, i, false) {
|
|
||||||
// If we are on a standalone node, save the indent info for partials
|
|
||||||
if partial, ok := current.(*ast.PartialStatement); ok {
|
|
||||||
// Pull out the whitespace from the final line
|
|
||||||
if i > 0 {
|
|
||||||
if prevContent, ok := body[i-1].(*ast.ContentStatement); ok {
|
|
||||||
partial.Indent = rPartialIndent.FindString(prevContent.Original)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if b, ok := current.(*ast.BlockStatement); ok {
|
|
||||||
if openStandalone {
|
|
||||||
prog := b.Program
|
|
||||||
if prog == nil {
|
|
||||||
prog = b.Inverse
|
|
||||||
}
|
|
||||||
|
|
||||||
omitRightFirst(prog.Body, false)
|
|
||||||
|
|
||||||
// Strip out the previous content node if it's whitespace only
|
|
||||||
omitLeft(body, i, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
if closeStandalone {
|
|
||||||
prog := b.Inverse
|
|
||||||
if prog == nil {
|
|
||||||
prog = b.Program
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always strip the next node
|
|
||||||
omitRight(body, i, false)
|
|
||||||
|
|
||||||
omitLeftLast(prog.Body, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *whitespaceVisitor) VisitBlock(block *ast.BlockStatement) interface{} {
|
|
||||||
if block.Program != nil {
|
|
||||||
block.Program.Accept(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if block.Inverse != nil {
|
|
||||||
block.Inverse.Accept(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
program := block.Program
|
|
||||||
inverse := block.Inverse
|
|
||||||
|
|
||||||
if program == nil {
|
|
||||||
program = inverse
|
|
||||||
inverse = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
firstInverse := inverse
|
|
||||||
lastInverse := inverse
|
|
||||||
|
|
||||||
if (inverse != nil) && inverse.Chained {
|
|
||||||
b, _ := inverse.Body[0].(*ast.BlockStatement)
|
|
||||||
firstInverse = b.Program
|
|
||||||
|
|
||||||
for lastInverse.Chained {
|
|
||||||
b, _ := lastInverse.Body[len(lastInverse.Body)-1].(*ast.BlockStatement)
|
|
||||||
lastInverse = b.Program
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closeProg := firstInverse
|
|
||||||
if closeProg == nil {
|
|
||||||
closeProg = program
|
|
||||||
}
|
|
||||||
|
|
||||||
strip := &ast.Strip{
|
|
||||||
Open: (block.OpenStrip != nil) && block.OpenStrip.Open,
|
|
||||||
Close: (block.CloseStrip != nil) && block.CloseStrip.Close,
|
|
||||||
|
|
||||||
OpenStandalone: isNextWhitespace(program.Body),
|
|
||||||
CloseStandalone: isPrevWhitespace(closeProg.Body),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block.OpenStrip != nil) && block.OpenStrip.Close {
|
|
||||||
omitRightFirst(program.Body, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if inverse != nil {
|
|
||||||
if block.InverseStrip != nil {
|
|
||||||
inverseStrip := block.InverseStrip
|
|
||||||
|
|
||||||
if inverseStrip.Open {
|
|
||||||
omitLeftLast(program.Body, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if inverseStrip.Close {
|
|
||||||
omitRightFirst(firstInverse.Body, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block.CloseStrip != nil) && block.CloseStrip.Open {
|
|
||||||
omitLeftLast(lastInverse.Body, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find standalone else statements
|
|
||||||
if isPrevWhitespace(program.Body) && isNextWhitespace(firstInverse.Body) {
|
|
||||||
omitLeftLast(program.Body, false)
|
|
||||||
|
|
||||||
omitRightFirst(firstInverse.Body, false)
|
|
||||||
}
|
|
||||||
} else if (block.CloseStrip != nil) && block.CloseStrip.Open {
|
|
||||||
omitLeftLast(program.Body, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return strip
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *whitespaceVisitor) VisitMustache(mustache *ast.MustacheStatement) interface{} {
|
|
||||||
return mustache.Strip
|
|
||||||
}
|
|
||||||
|
|
||||||
func _inlineStandalone(strip *ast.Strip) interface{} {
|
|
||||||
return &ast.Strip{
|
|
||||||
Open: strip.Open,
|
|
||||||
Close: strip.Close,
|
|
||||||
InlineStandalone: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *whitespaceVisitor) VisitPartial(node *ast.PartialStatement) interface{} {
|
|
||||||
strip := node.Strip
|
|
||||||
if strip == nil {
|
|
||||||
strip = &ast.Strip{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _inlineStandalone(strip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *whitespaceVisitor) VisitComment(node *ast.CommentStatement) interface{} {
|
|
||||||
strip := node.Strip
|
|
||||||
if strip == nil {
|
|
||||||
strip = &ast.Strip{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _inlineStandalone(strip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOOP
|
|
||||||
func (v *whitespaceVisitor) VisitContent(node *ast.ContentStatement) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitExpression(node *ast.Expression) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitSubExpression(node *ast.SubExpression) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitPath(node *ast.PathExpression) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitString(node *ast.StringLiteral) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitBoolean(node *ast.BooleanLiteral) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitNumber(node *ast.NumberLiteral) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitHash(node *ast.Hash) interface{} { return nil }
|
|
||||||
func (v *whitespaceVisitor) VisitHashPair(node *ast.HashPair) interface{} { return nil }
|
|
85
vendor/github.com/aymerick/raymond/partial.go
generated
vendored
85
vendor/github.com/aymerick/raymond/partial.go
generated
vendored
@ -1,85 +0,0 @@
|
|||||||
package raymond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// partial represents a partial template
|
|
||||||
type partial struct {
|
|
||||||
name string
|
|
||||||
source string
|
|
||||||
tpl *Template
|
|
||||||
}
|
|
||||||
|
|
||||||
// partials stores all global partials
|
|
||||||
var partials map[string]*partial
|
|
||||||
|
|
||||||
// protects global partials
|
|
||||||
var partialsMutex sync.RWMutex
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
partials = make(map[string]*partial)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newPartial instanciates a new partial
|
|
||||||
func newPartial(name string, source string, tpl *Template) *partial {
|
|
||||||
return &partial{
|
|
||||||
name: name,
|
|
||||||
source: source,
|
|
||||||
tpl: tpl,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartial registers a global partial. That partial will be available to all templates.
|
|
||||||
func RegisterPartial(name string, source string) {
|
|
||||||
partialsMutex.Lock()
|
|
||||||
defer partialsMutex.Unlock()
|
|
||||||
|
|
||||||
if partials[name] != nil {
|
|
||||||
panic(fmt.Errorf("Partial already registered: %s", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
partials[name] = newPartial(name, source, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartials registers several global partials. Those partials will be available to all templates.
|
|
||||||
func RegisterPartials(partials map[string]string) {
|
|
||||||
for name, p := range partials {
|
|
||||||
RegisterPartial(name, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartialTemplate registers a global partial with given parsed template. That partial will be available to all templates.
|
|
||||||
func RegisterPartialTemplate(name string, tpl *Template) {
|
|
||||||
partialsMutex.Lock()
|
|
||||||
defer partialsMutex.Unlock()
|
|
||||||
|
|
||||||
if partials[name] != nil {
|
|
||||||
panic(fmt.Errorf("Partial already registered: %s", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
partials[name] = newPartial(name, "", tpl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// findPartial finds a registered global partial
|
|
||||||
func findPartial(name string) *partial {
|
|
||||||
partialsMutex.RLock()
|
|
||||||
defer partialsMutex.RUnlock()
|
|
||||||
|
|
||||||
return partials[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// template returns parsed partial template
|
|
||||||
func (p *partial) template() (*Template, error) {
|
|
||||||
if p.tpl == nil {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
p.tpl, err = Parse(p.source)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.tpl, nil
|
|
||||||
}
|
|
28
vendor/github.com/aymerick/raymond/raymond.go
generated
vendored
28
vendor/github.com/aymerick/raymond/raymond.go
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
// Package raymond provides handlebars evaluation
|
|
||||||
package raymond
|
|
||||||
|
|
||||||
// Render parses a template and evaluates it with given context
|
|
||||||
//
|
|
||||||
// Note that this function call is not optimal as your template is parsed everytime you call it. You should use Parse() function instead.
|
|
||||||
func Render(source string, ctx interface{}) (string, error) {
|
|
||||||
// parse template
|
|
||||||
tpl, err := Parse(source)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// renders template
|
|
||||||
str, err := tpl.Exec(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return str, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustRender parses a template and evaluates it with given context. It panics on error.
|
|
||||||
//
|
|
||||||
// Note that this function call is not optimal as your template is parsed everytime you call it. You should use Parse() function instead.
|
|
||||||
func MustRender(source string, ctx interface{}) string {
|
|
||||||
return MustParse(source).MustExec(ctx)
|
|
||||||
}
|
|
BIN
vendor/github.com/aymerick/raymond/raymond.png
generated
vendored
BIN
vendor/github.com/aymerick/raymond/raymond.png
generated
vendored
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
84
vendor/github.com/aymerick/raymond/string.go
generated
vendored
84
vendor/github.com/aymerick/raymond/string.go
generated
vendored
@ -1,84 +0,0 @@
|
|||||||
package raymond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SafeString represents a string that must not be escaped.
|
|
||||||
//
|
|
||||||
// A SafeString can be returned by helpers to disable escaping.
|
|
||||||
type SafeString string
|
|
||||||
|
|
||||||
// isSafeString returns true if argument is a SafeString
|
|
||||||
func isSafeString(value interface{}) bool {
|
|
||||||
if _, ok := value.(SafeString); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Str returns string representation of any basic type value.
|
|
||||||
func Str(value interface{}) string {
|
|
||||||
return strValue(reflect.ValueOf(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
// strValue returns string representation of a reflect.Value
|
|
||||||
func strValue(value reflect.Value) string {
|
|
||||||
result := ""
|
|
||||||
|
|
||||||
ival, ok := printableValue(value)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Errorf("Can't print value: %q", value))
|
|
||||||
}
|
|
||||||
|
|
||||||
val := reflect.ValueOf(ival)
|
|
||||||
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Array, reflect.Slice:
|
|
||||||
for i := 0; i < val.Len(); i++ {
|
|
||||||
result += strValue(val.Index(i))
|
|
||||||
}
|
|
||||||
case reflect.Bool:
|
|
||||||
result = "false"
|
|
||||||
if val.Bool() {
|
|
||||||
result = "true"
|
|
||||||
}
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
result = fmt.Sprintf("%d", ival)
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
result = strconv.FormatFloat(val.Float(), 'f', -1, 64)
|
|
||||||
case reflect.Invalid:
|
|
||||||
result = ""
|
|
||||||
default:
|
|
||||||
result = fmt.Sprintf("%s", ival)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// printableValue returns the, possibly indirected, interface value inside v that
|
|
||||||
// is best for a call to formatted printer.
|
|
||||||
//
|
|
||||||
// NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
|
|
||||||
func printableValue(v reflect.Value) (interface{}, bool) {
|
|
||||||
if v.Kind() == reflect.Ptr {
|
|
||||||
v, _ = indirect(v) // fmt.Fprint handles nil.
|
|
||||||
}
|
|
||||||
if !v.IsValid() {
|
|
||||||
return "", true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !v.Type().Implements(errorType) && !v.Type().Implements(fmtStringerType) {
|
|
||||||
if v.CanAddr() && (reflect.PtrTo(v.Type()).Implements(errorType) || reflect.PtrTo(v.Type()).Implements(fmtStringerType)) {
|
|
||||||
v = v.Addr()
|
|
||||||
} else {
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func:
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v.Interface(), true
|
|
||||||
}
|
|
248
vendor/github.com/aymerick/raymond/template.go
generated
vendored
248
vendor/github.com/aymerick/raymond/template.go
generated
vendored
@ -1,248 +0,0 @@
|
|||||||
package raymond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/aymerick/raymond/ast"
|
|
||||||
"github.com/aymerick/raymond/parser"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Template represents a handlebars template.
|
|
||||||
type Template struct {
|
|
||||||
source string
|
|
||||||
program *ast.Program
|
|
||||||
helpers map[string]reflect.Value
|
|
||||||
partials map[string]*partial
|
|
||||||
mutex sync.RWMutex // protects helpers and partials
|
|
||||||
}
|
|
||||||
|
|
||||||
// newTemplate instanciate a new template without parsing it
|
|
||||||
func newTemplate(source string) *Template {
|
|
||||||
return &Template{
|
|
||||||
source: source,
|
|
||||||
helpers: make(map[string]reflect.Value),
|
|
||||||
partials: make(map[string]*partial),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse instanciates a template by parsing given source.
|
|
||||||
func Parse(source string) (*Template, error) {
|
|
||||||
tpl := newTemplate(source)
|
|
||||||
|
|
||||||
// parse template
|
|
||||||
if err := tpl.parse(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return tpl, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustParse instanciates a template by parsing given source. It panics on error.
|
|
||||||
func MustParse(source string) *Template {
|
|
||||||
result, err := Parse(source)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseFile reads given file and returns parsed template.
|
|
||||||
func ParseFile(filePath string) (*Template, error) {
|
|
||||||
b, err := ioutil.ReadFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return Parse(string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse parses the template
|
|
||||||
//
|
|
||||||
// It can be called several times, the parsing will be done only once.
|
|
||||||
func (tpl *Template) parse() error {
|
|
||||||
if tpl.program == nil {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
tpl.program, err = parser.Parse(tpl.source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clone returns a copy of that template.
|
|
||||||
func (tpl *Template) Clone() *Template {
|
|
||||||
result := newTemplate(tpl.source)
|
|
||||||
|
|
||||||
result.program = tpl.program
|
|
||||||
|
|
||||||
tpl.mutex.RLock()
|
|
||||||
defer tpl.mutex.RUnlock()
|
|
||||||
|
|
||||||
for name, helper := range tpl.helpers {
|
|
||||||
result.RegisterHelper(name, helper.Interface())
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, partial := range tpl.partials {
|
|
||||||
result.addPartial(name, partial.source, partial.tpl)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tpl *Template) findHelper(name string) reflect.Value {
|
|
||||||
tpl.mutex.RLock()
|
|
||||||
defer tpl.mutex.RUnlock()
|
|
||||||
|
|
||||||
return tpl.helpers[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterHelper registers a helper for that template.
|
|
||||||
func (tpl *Template) RegisterHelper(name string, helper interface{}) {
|
|
||||||
tpl.mutex.Lock()
|
|
||||||
defer tpl.mutex.Unlock()
|
|
||||||
|
|
||||||
if tpl.helpers[name] != zero {
|
|
||||||
panic(fmt.Sprintf("Helper %s already registered", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
val := reflect.ValueOf(helper)
|
|
||||||
ensureValidHelper(name, val)
|
|
||||||
|
|
||||||
tpl.helpers[name] = val
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterHelpers registers several helpers for that template.
|
|
||||||
func (tpl *Template) RegisterHelpers(helpers map[string]interface{}) {
|
|
||||||
for name, helper := range helpers {
|
|
||||||
tpl.RegisterHelper(name, helper)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tpl *Template) addPartial(name string, source string, template *Template) {
|
|
||||||
tpl.mutex.Lock()
|
|
||||||
defer tpl.mutex.Unlock()
|
|
||||||
|
|
||||||
if tpl.partials[name] != nil {
|
|
||||||
panic(fmt.Sprintf("Partial %s already registered", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
tpl.partials[name] = newPartial(name, source, template)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tpl *Template) findPartial(name string) *partial {
|
|
||||||
tpl.mutex.RLock()
|
|
||||||
defer tpl.mutex.RUnlock()
|
|
||||||
|
|
||||||
return tpl.partials[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartial registers a partial for that template.
|
|
||||||
func (tpl *Template) RegisterPartial(name string, source string) {
|
|
||||||
tpl.addPartial(name, source, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartials registers several partials for that template.
|
|
||||||
func (tpl *Template) RegisterPartials(partials map[string]string) {
|
|
||||||
for name, partial := range partials {
|
|
||||||
tpl.RegisterPartial(name, partial)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartialFile reads given file and registers its content as a partial with given name.
|
|
||||||
func (tpl *Template) RegisterPartialFile(filePath string, name string) error {
|
|
||||||
b, err := ioutil.ReadFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tpl.RegisterPartial(name, string(b))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartialFiles reads several files and registers them as partials, the filename base is used as the partial name.
|
|
||||||
func (tpl *Template) RegisterPartialFiles(filePaths ...string) error {
|
|
||||||
if len(filePaths) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, filePath := range filePaths {
|
|
||||||
name := fileBase(filePath)
|
|
||||||
|
|
||||||
if err := tpl.RegisterPartialFile(filePath, name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterPartialTemplate registers an already parsed partial for that template.
|
|
||||||
func (tpl *Template) RegisterPartialTemplate(name string, template *Template) {
|
|
||||||
tpl.addPartial(name, "", template)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec evaluates template with given context.
|
|
||||||
func (tpl *Template) Exec(ctx interface{}) (result string, err error) {
|
|
||||||
return tpl.ExecWith(ctx, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustExec evaluates template with given context. It panics on error.
|
|
||||||
func (tpl *Template) MustExec(ctx interface{}) string {
|
|
||||||
result, err := tpl.Exec(ctx)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecWith evaluates template with given context and private data frame.
|
|
||||||
func (tpl *Template) ExecWith(ctx interface{}, privData *DataFrame) (result string, err error) {
|
|
||||||
defer errRecover(&err)
|
|
||||||
|
|
||||||
// parses template if necessary
|
|
||||||
err = tpl.parse()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup visitor
|
|
||||||
v := newEvalVisitor(tpl, ctx, privData)
|
|
||||||
|
|
||||||
// visit AST
|
|
||||||
result, _ = tpl.program.Accept(v).(string)
|
|
||||||
|
|
||||||
// named return values
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// errRecover recovers evaluation panic
|
|
||||||
func errRecover(errp *error) {
|
|
||||||
e := recover()
|
|
||||||
if e != nil {
|
|
||||||
switch err := e.(type) {
|
|
||||||
case runtime.Error:
|
|
||||||
panic(e)
|
|
||||||
case error:
|
|
||||||
*errp = err
|
|
||||||
default:
|
|
||||||
panic(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrintAST returns string representation of parsed template.
|
|
||||||
func (tpl *Template) PrintAST() string {
|
|
||||||
if err := tpl.parse(); err != nil {
|
|
||||||
return fmt.Sprintf("PARSER ERROR: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ast.Print(tpl.program)
|
|
||||||
}
|
|
85
vendor/github.com/aymerick/raymond/utils.go
generated
vendored
85
vendor/github.com/aymerick/raymond/utils.go
generated
vendored
@ -1,85 +0,0 @@
|
|||||||
package raymond
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
// indirect returns the item at the end of indirection, and a bool to indicate if it's nil.
|
|
||||||
// We indirect through pointers and empty interfaces (only) because
|
|
||||||
// non-empty interfaces have methods we might need.
|
|
||||||
//
|
|
||||||
// NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
|
|
||||||
func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
|
|
||||||
for ; v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface; v = v.Elem() {
|
|
||||||
if v.IsNil() {
|
|
||||||
return v, true
|
|
||||||
}
|
|
||||||
if v.Kind() == reflect.Interface && v.NumMethod() > 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTrue returns true if obj is a truthy value.
|
|
||||||
func IsTrue(obj interface{}) bool {
|
|
||||||
thruth, ok := isTrueValue(reflect.ValueOf(obj))
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return thruth
|
|
||||||
}
|
|
||||||
|
|
||||||
// isTrueValue reports whether the value is 'true', in the sense of not the zero of its type,
|
|
||||||
// and whether the value has a meaningful truth value
|
|
||||||
//
|
|
||||||
// NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
|
|
||||||
func isTrueValue(val reflect.Value) (truth, ok bool) {
|
|
||||||
if !val.IsValid() {
|
|
||||||
// Something like var x interface{}, never set. It's a form of nil.
|
|
||||||
return false, true
|
|
||||||
}
|
|
||||||
switch val.Kind() {
|
|
||||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
|
||||||
truth = val.Len() > 0
|
|
||||||
case reflect.Bool:
|
|
||||||
truth = val.Bool()
|
|
||||||
case reflect.Complex64, reflect.Complex128:
|
|
||||||
truth = val.Complex() != 0
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface:
|
|
||||||
truth = !val.IsNil()
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
truth = val.Int() != 0
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
truth = val.Float() != 0
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
|
||||||
truth = val.Uint() != 0
|
|
||||||
case reflect.Struct:
|
|
||||||
truth = true // Struct values are always true.
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return truth, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
|
|
||||||
//
|
|
||||||
// NOTE: borrowed from https://github.com/golang/go/tree/master/src/text/template/exec.go
|
|
||||||
func canBeNil(typ reflect.Type) bool {
|
|
||||||
switch typ.Kind() {
|
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// fileBase returns base file name
|
|
||||||
//
|
|
||||||
// example: /foo/bar/baz.png => baz
|
|
||||||
func fileBase(filePath string) string {
|
|
||||||
fileName := path.Base(filePath)
|
|
||||||
fileExt := path.Ext(filePath)
|
|
||||||
|
|
||||||
return fileName[:len(fileName)-len(fileExt)]
|
|
||||||
}
|
|
15
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
15
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
ISC License
|
|
||||||
|
|
||||||
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software for any
|
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
152
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
152
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
@ -1,152 +0,0 @@
|
|||||||
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
|
||||||
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
|
||||||
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
|
||||||
// tag is deprecated and thus should not be used.
|
|
||||||
// +build !js,!appengine,!safe,!disableunsafe
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// UnsafeDisabled is a build-time constant which specifies whether or
|
|
||||||
// not access to the unsafe package is available.
|
|
||||||
UnsafeDisabled = false
|
|
||||||
|
|
||||||
// ptrSize is the size of a pointer on the current arch.
|
|
||||||
ptrSize = unsafe.Sizeof((*byte)(nil))
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
|
|
||||||
// internal reflect.Value fields. These values are valid before golang
|
|
||||||
// commit ecccf07e7f9d which changed the format. The are also valid
|
|
||||||
// after commit 82f48826c6c7 which changed the format again to mirror
|
|
||||||
// the original format. Code in the init function updates these offsets
|
|
||||||
// as necessary.
|
|
||||||
offsetPtr = uintptr(ptrSize)
|
|
||||||
offsetScalar = uintptr(0)
|
|
||||||
offsetFlag = uintptr(ptrSize * 2)
|
|
||||||
|
|
||||||
// flagKindWidth and flagKindShift indicate various bits that the
|
|
||||||
// reflect package uses internally to track kind information.
|
|
||||||
//
|
|
||||||
// flagRO indicates whether or not the value field of a reflect.Value is
|
|
||||||
// read-only.
|
|
||||||
//
|
|
||||||
// flagIndir indicates whether the value field of a reflect.Value is
|
|
||||||
// the actual data or a pointer to the data.
|
|
||||||
//
|
|
||||||
// These values are valid before golang commit 90a7c3c86944 which
|
|
||||||
// changed their positions. Code in the init function updates these
|
|
||||||
// flags as necessary.
|
|
||||||
flagKindWidth = uintptr(5)
|
|
||||||
flagKindShift = uintptr(flagKindWidth - 1)
|
|
||||||
flagRO = uintptr(1 << 0)
|
|
||||||
flagIndir = uintptr(1 << 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Older versions of reflect.Value stored small integers directly in the
|
|
||||||
// ptr field (which is named val in the older versions). Versions
|
|
||||||
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
|
|
||||||
// scalar for this purpose which unfortunately came before the flag
|
|
||||||
// field, so the offset of the flag field is different for those
|
|
||||||
// versions.
|
|
||||||
//
|
|
||||||
// This code constructs a new reflect.Value from a known small integer
|
|
||||||
// and checks if the size of the reflect.Value struct indicates it has
|
|
||||||
// the scalar field. When it does, the offsets are updated accordingly.
|
|
||||||
vv := reflect.ValueOf(0xf00)
|
|
||||||
if unsafe.Sizeof(vv) == (ptrSize * 4) {
|
|
||||||
offsetScalar = ptrSize * 2
|
|
||||||
offsetFlag = ptrSize * 3
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit 90a7c3c86944 changed the flag positions such that the low
|
|
||||||
// order bits are the kind. This code extracts the kind from the flags
|
|
||||||
// field and ensures it's the correct type. When it's not, the flag
|
|
||||||
// order has been changed to the newer format, so the flags are updated
|
|
||||||
// accordingly.
|
|
||||||
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
|
|
||||||
upfv := *(*uintptr)(upf)
|
|
||||||
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
|
|
||||||
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
|
|
||||||
flagKindShift = 0
|
|
||||||
flagRO = 1 << 5
|
|
||||||
flagIndir = 1 << 6
|
|
||||||
|
|
||||||
// Commit adf9b30e5594 modified the flags to separate the
|
|
||||||
// flagRO flag into two bits which specifies whether or not the
|
|
||||||
// field is embedded. This causes flagIndir to move over a bit
|
|
||||||
// and means that flagRO is the combination of either of the
|
|
||||||
// original flagRO bit and the new bit.
|
|
||||||
//
|
|
||||||
// This code detects the change by extracting what used to be
|
|
||||||
// the indirect bit to ensure it's set. When it's not, the flag
|
|
||||||
// order has been changed to the newer format, so the flags are
|
|
||||||
// updated accordingly.
|
|
||||||
if upfv&flagIndir == 0 {
|
|
||||||
flagRO = 3 << 5
|
|
||||||
flagIndir = 1 << 7
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
|
||||||
// the typical safety restrictions preventing access to unaddressable and
|
|
||||||
// unexported data. It works by digging the raw pointer to the underlying
|
|
||||||
// value out of the protected value and generating a new unprotected (unsafe)
|
|
||||||
// reflect.Value to it.
|
|
||||||
//
|
|
||||||
// This allows us to check for implementations of the Stringer and error
|
|
||||||
// interfaces to be used for pretty printing ordinarily unaddressable and
|
|
||||||
// inaccessible values such as unexported struct fields.
|
|
||||||
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
|
||||||
indirects := 1
|
|
||||||
vt := v.Type()
|
|
||||||
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
|
|
||||||
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
|
|
||||||
if rvf&flagIndir != 0 {
|
|
||||||
vt = reflect.PtrTo(v.Type())
|
|
||||||
indirects++
|
|
||||||
} else if offsetScalar != 0 {
|
|
||||||
// The value is in the scalar field when it's not one of the
|
|
||||||
// reference types.
|
|
||||||
switch vt.Kind() {
|
|
||||||
case reflect.Uintptr:
|
|
||||||
case reflect.Chan:
|
|
||||||
case reflect.Func:
|
|
||||||
case reflect.Map:
|
|
||||||
case reflect.Ptr:
|
|
||||||
case reflect.UnsafePointer:
|
|
||||||
default:
|
|
||||||
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
|
|
||||||
offsetScalar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pv := reflect.NewAt(vt, upv)
|
|
||||||
rv = pv
|
|
||||||
for i := 0; i < indirects; i++ {
|
|
||||||
rv = rv.Elem()
|
|
||||||
}
|
|
||||||
return rv
|
|
||||||
}
|
|
38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
38
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
|
||||||
// when the code is running on Google App Engine, compiled by GopherJS, or
|
|
||||||
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
|
||||||
// tag is deprecated and thus should not be used.
|
|
||||||
// +build js appengine safe disableunsafe
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import "reflect"
|
|
||||||
|
|
||||||
const (
|
|
||||||
// UnsafeDisabled is a build-time constant which specifies whether or
|
|
||||||
// not access to the unsafe package is available.
|
|
||||||
UnsafeDisabled = true
|
|
||||||
)
|
|
||||||
|
|
||||||
// unsafeReflectValue typically converts the passed reflect.Value into a one
|
|
||||||
// that bypasses the typical safety restrictions preventing access to
|
|
||||||
// unaddressable and unexported data. However, doing this relies on access to
|
|
||||||
// the unsafe package. This is a stub version which simply returns the passed
|
|
||||||
// reflect.Value when the unsafe package is not available.
|
|
||||||
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
|
||||||
return v
|
|
||||||
}
|
|
341
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
341
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
@ -1,341 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Some constants in the form of bytes to avoid string overhead. This mirrors
|
|
||||||
// the technique used in the fmt package.
|
|
||||||
var (
|
|
||||||
panicBytes = []byte("(PANIC=")
|
|
||||||
plusBytes = []byte("+")
|
|
||||||
iBytes = []byte("i")
|
|
||||||
trueBytes = []byte("true")
|
|
||||||
falseBytes = []byte("false")
|
|
||||||
interfaceBytes = []byte("(interface {})")
|
|
||||||
commaNewlineBytes = []byte(",\n")
|
|
||||||
newlineBytes = []byte("\n")
|
|
||||||
openBraceBytes = []byte("{")
|
|
||||||
openBraceNewlineBytes = []byte("{\n")
|
|
||||||
closeBraceBytes = []byte("}")
|
|
||||||
asteriskBytes = []byte("*")
|
|
||||||
colonBytes = []byte(":")
|
|
||||||
colonSpaceBytes = []byte(": ")
|
|
||||||
openParenBytes = []byte("(")
|
|
||||||
closeParenBytes = []byte(")")
|
|
||||||
spaceBytes = []byte(" ")
|
|
||||||
pointerChainBytes = []byte("->")
|
|
||||||
nilAngleBytes = []byte("<nil>")
|
|
||||||
maxNewlineBytes = []byte("<max depth reached>\n")
|
|
||||||
maxShortBytes = []byte("<max>")
|
|
||||||
circularBytes = []byte("<already shown>")
|
|
||||||
circularShortBytes = []byte("<shown>")
|
|
||||||
invalidAngleBytes = []byte("<invalid>")
|
|
||||||
openBracketBytes = []byte("[")
|
|
||||||
closeBracketBytes = []byte("]")
|
|
||||||
percentBytes = []byte("%")
|
|
||||||
precisionBytes = []byte(".")
|
|
||||||
openAngleBytes = []byte("<")
|
|
||||||
closeAngleBytes = []byte(">")
|
|
||||||
openMapBytes = []byte("map[")
|
|
||||||
closeMapBytes = []byte("]")
|
|
||||||
lenEqualsBytes = []byte("len=")
|
|
||||||
capEqualsBytes = []byte("cap=")
|
|
||||||
)
|
|
||||||
|
|
||||||
// hexDigits is used to map a decimal value to a hex digit.
|
|
||||||
var hexDigits = "0123456789abcdef"
|
|
||||||
|
|
||||||
// catchPanic handles any panics that might occur during the handleMethods
|
|
||||||
// calls.
|
|
||||||
func catchPanic(w io.Writer, v reflect.Value) {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
w.Write(panicBytes)
|
|
||||||
fmt.Fprintf(w, "%v", err)
|
|
||||||
w.Write(closeParenBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleMethods attempts to call the Error and String methods on the underlying
|
|
||||||
// type the passed reflect.Value represents and outputes the result to Writer w.
|
|
||||||
//
|
|
||||||
// It handles panics in any called methods by catching and displaying the error
|
|
||||||
// as the formatted value.
|
|
||||||
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
|
|
||||||
// We need an interface to check if the type implements the error or
|
|
||||||
// Stringer interface. However, the reflect package won't give us an
|
|
||||||
// interface on certain things like unexported struct fields in order
|
|
||||||
// to enforce visibility rules. We use unsafe, when it's available,
|
|
||||||
// to bypass these restrictions since this package does not mutate the
|
|
||||||
// values.
|
|
||||||
if !v.CanInterface() {
|
|
||||||
if UnsafeDisabled {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
v = unsafeReflectValue(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Choose whether or not to do error and Stringer interface lookups against
|
|
||||||
// the base type or a pointer to the base type depending on settings.
|
|
||||||
// Technically calling one of these methods with a pointer receiver can
|
|
||||||
// mutate the value, however, types which choose to satisify an error or
|
|
||||||
// Stringer interface with a pointer receiver should not be mutating their
|
|
||||||
// state inside these interface methods.
|
|
||||||
if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
|
|
||||||
v = unsafeReflectValue(v)
|
|
||||||
}
|
|
||||||
if v.CanAddr() {
|
|
||||||
v = v.Addr()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it an error or Stringer?
|
|
||||||
switch iface := v.Interface().(type) {
|
|
||||||
case error:
|
|
||||||
defer catchPanic(w, v)
|
|
||||||
if cs.ContinueOnMethod {
|
|
||||||
w.Write(openParenBytes)
|
|
||||||
w.Write([]byte(iface.Error()))
|
|
||||||
w.Write(closeParenBytes)
|
|
||||||
w.Write(spaceBytes)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte(iface.Error()))
|
|
||||||
return true
|
|
||||||
|
|
||||||
case fmt.Stringer:
|
|
||||||
defer catchPanic(w, v)
|
|
||||||
if cs.ContinueOnMethod {
|
|
||||||
w.Write(openParenBytes)
|
|
||||||
w.Write([]byte(iface.String()))
|
|
||||||
w.Write(closeParenBytes)
|
|
||||||
w.Write(spaceBytes)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
w.Write([]byte(iface.String()))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// printBool outputs a boolean value as true or false to Writer w.
|
|
||||||
func printBool(w io.Writer, val bool) {
|
|
||||||
if val {
|
|
||||||
w.Write(trueBytes)
|
|
||||||
} else {
|
|
||||||
w.Write(falseBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// printInt outputs a signed integer value to Writer w.
|
|
||||||
func printInt(w io.Writer, val int64, base int) {
|
|
||||||
w.Write([]byte(strconv.FormatInt(val, base)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// printUint outputs an unsigned integer value to Writer w.
|
|
||||||
func printUint(w io.Writer, val uint64, base int) {
|
|
||||||
w.Write([]byte(strconv.FormatUint(val, base)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// printFloat outputs a floating point value using the specified precision,
|
|
||||||
// which is expected to be 32 or 64bit, to Writer w.
|
|
||||||
func printFloat(w io.Writer, val float64, precision int) {
|
|
||||||
w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// printComplex outputs a complex value using the specified float precision
|
|
||||||
// for the real and imaginary parts to Writer w.
|
|
||||||
func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
|
||||||
r := real(c)
|
|
||||||
w.Write(openParenBytes)
|
|
||||||
w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
|
|
||||||
i := imag(c)
|
|
||||||
if i >= 0 {
|
|
||||||
w.Write(plusBytes)
|
|
||||||
}
|
|
||||||
w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
|
|
||||||
w.Write(iBytes)
|
|
||||||
w.Write(closeParenBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
|
|
||||||
// prefix to Writer w.
|
|
||||||
func printHexPtr(w io.Writer, p uintptr) {
|
|
||||||
// Null pointer.
|
|
||||||
num := uint64(p)
|
|
||||||
if num == 0 {
|
|
||||||
w.Write(nilAngleBytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
|
|
||||||
buf := make([]byte, 18)
|
|
||||||
|
|
||||||
// It's simpler to construct the hex string right to left.
|
|
||||||
base := uint64(16)
|
|
||||||
i := len(buf) - 1
|
|
||||||
for num >= base {
|
|
||||||
buf[i] = hexDigits[num%base]
|
|
||||||
num /= base
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
buf[i] = hexDigits[num]
|
|
||||||
|
|
||||||
// Add '0x' prefix.
|
|
||||||
i--
|
|
||||||
buf[i] = 'x'
|
|
||||||
i--
|
|
||||||
buf[i] = '0'
|
|
||||||
|
|
||||||
// Strip unused leading bytes.
|
|
||||||
buf = buf[i:]
|
|
||||||
w.Write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// valuesSorter implements sort.Interface to allow a slice of reflect.Value
|
|
||||||
// elements to be sorted.
|
|
||||||
type valuesSorter struct {
|
|
||||||
values []reflect.Value
|
|
||||||
strings []string // either nil or same len and values
|
|
||||||
cs *ConfigState
|
|
||||||
}
|
|
||||||
|
|
||||||
// newValuesSorter initializes a valuesSorter instance, which holds a set of
|
|
||||||
// surrogate keys on which the data should be sorted. It uses flags in
|
|
||||||
// ConfigState to decide if and how to populate those surrogate keys.
|
|
||||||
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
|
|
||||||
vs := &valuesSorter{values: values, cs: cs}
|
|
||||||
if canSortSimply(vs.values[0].Kind()) {
|
|
||||||
return vs
|
|
||||||
}
|
|
||||||
if !cs.DisableMethods {
|
|
||||||
vs.strings = make([]string, len(values))
|
|
||||||
for i := range vs.values {
|
|
||||||
b := bytes.Buffer{}
|
|
||||||
if !handleMethods(cs, &b, vs.values[i]) {
|
|
||||||
vs.strings = nil
|
|
||||||
break
|
|
||||||
}
|
|
||||||
vs.strings[i] = b.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if vs.strings == nil && cs.SpewKeys {
|
|
||||||
vs.strings = make([]string, len(values))
|
|
||||||
for i := range vs.values {
|
|
||||||
vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vs
|
|
||||||
}
|
|
||||||
|
|
||||||
// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
|
|
||||||
// directly, or whether it should be considered for sorting by surrogate keys
|
|
||||||
// (if the ConfigState allows it).
|
|
||||||
func canSortSimply(kind reflect.Kind) bool {
|
|
||||||
// This switch parallels valueSortLess, except for the default case.
|
|
||||||
switch kind {
|
|
||||||
case reflect.Bool:
|
|
||||||
return true
|
|
||||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
|
||||||
return true
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
|
||||||
return true
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return true
|
|
||||||
case reflect.String:
|
|
||||||
return true
|
|
||||||
case reflect.Uintptr:
|
|
||||||
return true
|
|
||||||
case reflect.Array:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of values in the slice. It is part of the
|
|
||||||
// sort.Interface implementation.
|
|
||||||
func (s *valuesSorter) Len() int {
|
|
||||||
return len(s.values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap swaps the values at the passed indices. It is part of the
|
|
||||||
// sort.Interface implementation.
|
|
||||||
func (s *valuesSorter) Swap(i, j int) {
|
|
||||||
s.values[i], s.values[j] = s.values[j], s.values[i]
|
|
||||||
if s.strings != nil {
|
|
||||||
s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// valueSortLess returns whether the first value should sort before the second
|
|
||||||
// value. It is used by valueSorter.Less as part of the sort.Interface
|
|
||||||
// implementation.
|
|
||||||
func valueSortLess(a, b reflect.Value) bool {
|
|
||||||
switch a.Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
return !a.Bool() && b.Bool()
|
|
||||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
|
||||||
return a.Int() < b.Int()
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
|
||||||
return a.Uint() < b.Uint()
|
|
||||||
case reflect.Float32, reflect.Float64:
|
|
||||||
return a.Float() < b.Float()
|
|
||||||
case reflect.String:
|
|
||||||
return a.String() < b.String()
|
|
||||||
case reflect.Uintptr:
|
|
||||||
return a.Uint() < b.Uint()
|
|
||||||
case reflect.Array:
|
|
||||||
// Compare the contents of both arrays.
|
|
||||||
l := a.Len()
|
|
||||||
for i := 0; i < l; i++ {
|
|
||||||
av := a.Index(i)
|
|
||||||
bv := b.Index(i)
|
|
||||||
if av.Interface() == bv.Interface() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return valueSortLess(av, bv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a.String() < b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Less returns whether the value at index i should sort before the
|
|
||||||
// value at index j. It is part of the sort.Interface implementation.
|
|
||||||
func (s *valuesSorter) Less(i, j int) bool {
|
|
||||||
if s.strings == nil {
|
|
||||||
return valueSortLess(s.values[i], s.values[j])
|
|
||||||
}
|
|
||||||
return s.strings[i] < s.strings[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
// sortValues is a sort function that handles both native types and any type that
|
|
||||||
// can be converted to error or Stringer. Other inputs are sorted according to
|
|
||||||
// their Value.String() value to ensure display stability.
|
|
||||||
func sortValues(values []reflect.Value, cs *ConfigState) {
|
|
||||||
if len(values) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sort.Sort(newValuesSorter(values, cs))
|
|
||||||
}
|
|
306
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
306
vendor/github.com/davecgh/go-spew/spew/config.go
generated
vendored
@ -1,306 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ConfigState houses the configuration options used by spew to format and
|
|
||||||
// display values. There is a global instance, Config, that is used to control
|
|
||||||
// all top-level Formatter and Dump functionality. Each ConfigState instance
|
|
||||||
// provides methods equivalent to the top-level functions.
|
|
||||||
//
|
|
||||||
// The zero value for ConfigState provides no indentation. You would typically
|
|
||||||
// want to set it to a space or a tab.
|
|
||||||
//
|
|
||||||
// Alternatively, you can use NewDefaultConfig to get a ConfigState instance
|
|
||||||
// with default settings. See the documentation of NewDefaultConfig for default
|
|
||||||
// values.
|
|
||||||
type ConfigState struct {
|
|
||||||
// Indent specifies the string to use for each indentation level. The
|
|
||||||
// global config instance that all top-level functions use set this to a
|
|
||||||
// single space by default. If you would like more indentation, you might
|
|
||||||
// set this to a tab with "\t" or perhaps two spaces with " ".
|
|
||||||
Indent string
|
|
||||||
|
|
||||||
// MaxDepth controls the maximum number of levels to descend into nested
|
|
||||||
// data structures. The default, 0, means there is no limit.
|
|
||||||
//
|
|
||||||
// NOTE: Circular data structures are properly detected, so it is not
|
|
||||||
// necessary to set this value unless you specifically want to limit deeply
|
|
||||||
// nested data structures.
|
|
||||||
MaxDepth int
|
|
||||||
|
|
||||||
// DisableMethods specifies whether or not error and Stringer interfaces are
|
|
||||||
// invoked for types that implement them.
|
|
||||||
DisableMethods bool
|
|
||||||
|
|
||||||
// DisablePointerMethods specifies whether or not to check for and invoke
|
|
||||||
// error and Stringer interfaces on types which only accept a pointer
|
|
||||||
// receiver when the current type is not a pointer.
|
|
||||||
//
|
|
||||||
// NOTE: This might be an unsafe action since calling one of these methods
|
|
||||||
// with a pointer receiver could technically mutate the value, however,
|
|
||||||
// in practice, types which choose to satisify an error or Stringer
|
|
||||||
// interface with a pointer receiver should not be mutating their state
|
|
||||||
// inside these interface methods. As a result, this option relies on
|
|
||||||
// access to the unsafe package, so it will not have any effect when
|
|
||||||
// running in environments without access to the unsafe package such as
|
|
||||||
// Google App Engine or with the "safe" build tag specified.
|
|
||||||
DisablePointerMethods bool
|
|
||||||
|
|
||||||
// DisablePointerAddresses specifies whether to disable the printing of
|
|
||||||
// pointer addresses. This is useful when diffing data structures in tests.
|
|
||||||
DisablePointerAddresses bool
|
|
||||||
|
|
||||||
// DisableCapacities specifies whether to disable the printing of capacities
|
|
||||||
// for arrays, slices, maps and channels. This is useful when diffing
|
|
||||||
// data structures in tests.
|
|
||||||
DisableCapacities bool
|
|
||||||
|
|
||||||
// ContinueOnMethod specifies whether or not recursion should continue once
|
|
||||||
// a custom error or Stringer interface is invoked. The default, false,
|
|
||||||
// means it will print the results of invoking the custom error or Stringer
|
|
||||||
// interface and return immediately instead of continuing to recurse into
|
|
||||||
// the internals of the data type.
|
|
||||||
//
|
|
||||||
// NOTE: This flag does not have any effect if method invocation is disabled
|
|
||||||
// via the DisableMethods or DisablePointerMethods options.
|
|
||||||
ContinueOnMethod bool
|
|
||||||
|
|
||||||
// SortKeys specifies map keys should be sorted before being printed. Use
|
|
||||||
// this to have a more deterministic, diffable output. Note that only
|
|
||||||
// native types (bool, int, uint, floats, uintptr and string) and types
|
|
||||||
// that support the error or Stringer interfaces (if methods are
|
|
||||||
// enabled) are supported, with other types sorted according to the
|
|
||||||
// reflect.Value.String() output which guarantees display stability.
|
|
||||||
SortKeys bool
|
|
||||||
|
|
||||||
// SpewKeys specifies that, as a last resort attempt, map keys should
|
|
||||||
// be spewed to strings and sorted by those strings. This is only
|
|
||||||
// considered if SortKeys is true.
|
|
||||||
SpewKeys bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config is the active configuration of the top-level functions.
|
|
||||||
// The configuration can be changed by modifying the contents of spew.Config.
|
|
||||||
var Config = ConfigState{Indent: " "}
|
|
||||||
|
|
||||||
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the formatted string as a value that satisfies error. See NewFormatter
|
|
||||||
// for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) {
|
|
||||||
return fmt.Errorf(format, c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Fprint(w, c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Fprintf(w, format, c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Fprintln(w, c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Print(c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Print(c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Printf(format, c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Println(c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Println(c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the resulting string. See NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Sprint(a ...interface{}) string {
|
|
||||||
return fmt.Sprint(c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
|
||||||
// passed with a Formatter interface returned by c.NewFormatter. It returns
|
|
||||||
// the resulting string. See NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
|
|
||||||
return fmt.Sprintf(format, c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
|
||||||
// were passed with a Formatter interface returned by c.NewFormatter. It
|
|
||||||
// returns the resulting string. See NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b))
|
|
||||||
func (c *ConfigState) Sprintln(a ...interface{}) string {
|
|
||||||
return fmt.Sprintln(c.convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
|
||||||
interface. As a result, it integrates cleanly with standard fmt package
|
|
||||||
printing functions. The formatter is useful for inline printing of smaller data
|
|
||||||
types similar to the standard %v format specifier.
|
|
||||||
|
|
||||||
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
|
||||||
addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb
|
|
||||||
combinations. Any other verbs such as %x and %q will be sent to the the
|
|
||||||
standard fmt package for formatting. In addition, the custom formatter ignores
|
|
||||||
the width and precision arguments (however they will still work on the format
|
|
||||||
specifiers not handled by the custom formatter).
|
|
||||||
|
|
||||||
Typically this function shouldn't be called directly. It is much easier to make
|
|
||||||
use of the custom formatter by calling one of the convenience functions such as
|
|
||||||
c.Printf, c.Println, or c.Printf.
|
|
||||||
*/
|
|
||||||
func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
|
|
||||||
return newFormatter(c, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
|
||||||
// exactly the same as Dump.
|
|
||||||
func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
|
|
||||||
fdump(c, w, a...)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Dump displays the passed parameters to standard out with newlines, customizable
|
|
||||||
indentation, and additional debug information such as complete types and all
|
|
||||||
pointer addresses used to indirect to the final value. It provides the
|
|
||||||
following features over the built-in printing facilities provided by the fmt
|
|
||||||
package:
|
|
||||||
|
|
||||||
* Pointers are dereferenced and followed
|
|
||||||
* Circular data structures are detected and handled properly
|
|
||||||
* Custom Stringer/error interfaces are optionally invoked, including
|
|
||||||
on unexported types
|
|
||||||
* Custom types which only implement the Stringer/error interfaces via
|
|
||||||
a pointer receiver are optionally invoked when passing non-pointer
|
|
||||||
variables
|
|
||||||
* Byte arrays and slices are dumped like the hexdump -C command which
|
|
||||||
includes offsets, byte values in hex, and ASCII output
|
|
||||||
|
|
||||||
The configuration options are controlled by modifying the public members
|
|
||||||
of c. See ConfigState for options documentation.
|
|
||||||
|
|
||||||
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
|
||||||
get the formatted result as a string.
|
|
||||||
*/
|
|
||||||
func (c *ConfigState) Dump(a ...interface{}) {
|
|
||||||
fdump(c, os.Stdout, a...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sdump returns a string with the passed arguments formatted exactly the same
|
|
||||||
// as Dump.
|
|
||||||
func (c *ConfigState) Sdump(a ...interface{}) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
fdump(c, &buf, a...)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertArgs accepts a slice of arguments and returns a slice of the same
|
|
||||||
// length with each argument converted to a spew Formatter interface using
|
|
||||||
// the ConfigState associated with s.
|
|
||||||
func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) {
|
|
||||||
formatters = make([]interface{}, len(args))
|
|
||||||
for index, arg := range args {
|
|
||||||
formatters[index] = newFormatter(c, arg)
|
|
||||||
}
|
|
||||||
return formatters
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDefaultConfig returns a ConfigState with the following default settings.
|
|
||||||
//
|
|
||||||
// Indent: " "
|
|
||||||
// MaxDepth: 0
|
|
||||||
// DisableMethods: false
|
|
||||||
// DisablePointerMethods: false
|
|
||||||
// ContinueOnMethod: false
|
|
||||||
// SortKeys: false
|
|
||||||
func NewDefaultConfig() *ConfigState {
|
|
||||||
return &ConfigState{Indent: " "}
|
|
||||||
}
|
|
211
vendor/github.com/davecgh/go-spew/spew/doc.go
generated
vendored
211
vendor/github.com/davecgh/go-spew/spew/doc.go
generated
vendored
@ -1,211 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Package spew implements a deep pretty printer for Go data structures to aid in
|
|
||||||
debugging.
|
|
||||||
|
|
||||||
A quick overview of the additional features spew provides over the built-in
|
|
||||||
printing facilities for Go data types are as follows:
|
|
||||||
|
|
||||||
* Pointers are dereferenced and followed
|
|
||||||
* Circular data structures are detected and handled properly
|
|
||||||
* Custom Stringer/error interfaces are optionally invoked, including
|
|
||||||
on unexported types
|
|
||||||
* Custom types which only implement the Stringer/error interfaces via
|
|
||||||
a pointer receiver are optionally invoked when passing non-pointer
|
|
||||||
variables
|
|
||||||
* Byte arrays and slices are dumped like the hexdump -C command which
|
|
||||||
includes offsets, byte values in hex, and ASCII output (only when using
|
|
||||||
Dump style)
|
|
||||||
|
|
||||||
There are two different approaches spew allows for dumping Go data structures:
|
|
||||||
|
|
||||||
* Dump style which prints with newlines, customizable indentation,
|
|
||||||
and additional debug information such as types and all pointer addresses
|
|
||||||
used to indirect to the final value
|
|
||||||
* A custom Formatter interface that integrates cleanly with the standard fmt
|
|
||||||
package and replaces %v, %+v, %#v, and %#+v to provide inline printing
|
|
||||||
similar to the default %v while providing the additional functionality
|
|
||||||
outlined above and passing unsupported format verbs such as %x and %q
|
|
||||||
along to fmt
|
|
||||||
|
|
||||||
Quick Start
|
|
||||||
|
|
||||||
This section demonstrates how to quickly get started with spew. See the
|
|
||||||
sections below for further details on formatting and configuration options.
|
|
||||||
|
|
||||||
To dump a variable with full newlines, indentation, type, and pointer
|
|
||||||
information use Dump, Fdump, or Sdump:
|
|
||||||
spew.Dump(myVar1, myVar2, ...)
|
|
||||||
spew.Fdump(someWriter, myVar1, myVar2, ...)
|
|
||||||
str := spew.Sdump(myVar1, myVar2, ...)
|
|
||||||
|
|
||||||
Alternatively, if you would prefer to use format strings with a compacted inline
|
|
||||||
printing style, use the convenience wrappers Printf, Fprintf, etc with
|
|
||||||
%v (most compact), %+v (adds pointer addresses), %#v (adds types), or
|
|
||||||
%#+v (adds types and pointer addresses):
|
|
||||||
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
|
||||||
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
|
||||||
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
|
||||||
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
|
||||||
|
|
||||||
Configuration Options
|
|
||||||
|
|
||||||
Configuration of spew is handled by fields in the ConfigState type. For
|
|
||||||
convenience, all of the top-level functions use a global state available
|
|
||||||
via the spew.Config global.
|
|
||||||
|
|
||||||
It is also possible to create a ConfigState instance that provides methods
|
|
||||||
equivalent to the top-level functions. This allows concurrent configuration
|
|
||||||
options. See the ConfigState documentation for more details.
|
|
||||||
|
|
||||||
The following configuration options are available:
|
|
||||||
* Indent
|
|
||||||
String to use for each indentation level for Dump functions.
|
|
||||||
It is a single space by default. A popular alternative is "\t".
|
|
||||||
|
|
||||||
* MaxDepth
|
|
||||||
Maximum number of levels to descend into nested data structures.
|
|
||||||
There is no limit by default.
|
|
||||||
|
|
||||||
* DisableMethods
|
|
||||||
Disables invocation of error and Stringer interface methods.
|
|
||||||
Method invocation is enabled by default.
|
|
||||||
|
|
||||||
* DisablePointerMethods
|
|
||||||
Disables invocation of error and Stringer interface methods on types
|
|
||||||
which only accept pointer receivers from non-pointer variables.
|
|
||||||
Pointer method invocation is enabled by default.
|
|
||||||
|
|
||||||
* DisablePointerAddresses
|
|
||||||
DisablePointerAddresses specifies whether to disable the printing of
|
|
||||||
pointer addresses. This is useful when diffing data structures in tests.
|
|
||||||
|
|
||||||
* DisableCapacities
|
|
||||||
DisableCapacities specifies whether to disable the printing of
|
|
||||||
capacities for arrays, slices, maps and channels. This is useful when
|
|
||||||
diffing data structures in tests.
|
|
||||||
|
|
||||||
* ContinueOnMethod
|
|
||||||
Enables recursion into types after invoking error and Stringer interface
|
|
||||||
methods. Recursion after method invocation is disabled by default.
|
|
||||||
|
|
||||||
* SortKeys
|
|
||||||
Specifies map keys should be sorted before being printed. Use
|
|
||||||
this to have a more deterministic, diffable output. Note that
|
|
||||||
only native types (bool, int, uint, floats, uintptr and string)
|
|
||||||
and types which implement error or Stringer interfaces are
|
|
||||||
supported with other types sorted according to the
|
|
||||||
reflect.Value.String() output which guarantees display
|
|
||||||
stability. Natural map order is used by default.
|
|
||||||
|
|
||||||
* SpewKeys
|
|
||||||
Specifies that, as a last resort attempt, map keys should be
|
|
||||||
spewed to strings and sorted by those strings. This is only
|
|
||||||
considered if SortKeys is true.
|
|
||||||
|
|
||||||
Dump Usage
|
|
||||||
|
|
||||||
Simply call spew.Dump with a list of variables you want to dump:
|
|
||||||
|
|
||||||
spew.Dump(myVar1, myVar2, ...)
|
|
||||||
|
|
||||||
You may also call spew.Fdump if you would prefer to output to an arbitrary
|
|
||||||
io.Writer. For example, to dump to standard error:
|
|
||||||
|
|
||||||
spew.Fdump(os.Stderr, myVar1, myVar2, ...)
|
|
||||||
|
|
||||||
A third option is to call spew.Sdump to get the formatted output as a string:
|
|
||||||
|
|
||||||
str := spew.Sdump(myVar1, myVar2, ...)
|
|
||||||
|
|
||||||
Sample Dump Output
|
|
||||||
|
|
||||||
See the Dump example for details on the setup of the types and variables being
|
|
||||||
shown here.
|
|
||||||
|
|
||||||
(main.Foo) {
|
|
||||||
unexportedField: (*main.Bar)(0xf84002e210)({
|
|
||||||
flag: (main.Flag) flagTwo,
|
|
||||||
data: (uintptr) <nil>
|
|
||||||
}),
|
|
||||||
ExportedField: (map[interface {}]interface {}) (len=1) {
|
|
||||||
(string) (len=3) "one": (bool) true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C
|
|
||||||
command as shown.
|
|
||||||
([]uint8) (len=32 cap=32) {
|
|
||||||
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
|
||||||
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
|
||||||
00000020 31 32 |12|
|
|
||||||
}
|
|
||||||
|
|
||||||
Custom Formatter
|
|
||||||
|
|
||||||
Spew provides a custom formatter that implements the fmt.Formatter interface
|
|
||||||
so that it integrates cleanly with standard fmt package printing functions. The
|
|
||||||
formatter is useful for inline printing of smaller data types similar to the
|
|
||||||
standard %v format specifier.
|
|
||||||
|
|
||||||
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
|
||||||
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
|
||||||
combinations. Any other verbs such as %x and %q will be sent to the the
|
|
||||||
standard fmt package for formatting. In addition, the custom formatter ignores
|
|
||||||
the width and precision arguments (however they will still work on the format
|
|
||||||
specifiers not handled by the custom formatter).
|
|
||||||
|
|
||||||
Custom Formatter Usage
|
|
||||||
|
|
||||||
The simplest way to make use of the spew custom formatter is to call one of the
|
|
||||||
convenience functions such as spew.Printf, spew.Println, or spew.Printf. The
|
|
||||||
functions have syntax you are most likely already familiar with:
|
|
||||||
|
|
||||||
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
|
||||||
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
|
||||||
spew.Println(myVar, myVar2)
|
|
||||||
spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
|
||||||
spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
|
||||||
|
|
||||||
See the Index for the full list convenience functions.
|
|
||||||
|
|
||||||
Sample Formatter Output
|
|
||||||
|
|
||||||
Double pointer to a uint8:
|
|
||||||
%v: <**>5
|
|
||||||
%+v: <**>(0xf8400420d0->0xf8400420c8)5
|
|
||||||
%#v: (**uint8)5
|
|
||||||
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
|
|
||||||
|
|
||||||
Pointer to circular struct with a uint8 field and a pointer to itself:
|
|
||||||
%v: <*>{1 <*><shown>}
|
|
||||||
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
|
|
||||||
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
|
|
||||||
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
|
|
||||||
|
|
||||||
See the Printf example for details on the setup of variables being shown
|
|
||||||
here.
|
|
||||||
|
|
||||||
Errors
|
|
||||||
|
|
||||||
Since it is possible for custom Stringer/error interfaces to panic, spew
|
|
||||||
detects them and handles them internally by printing the panic information
|
|
||||||
inline with the output. Since spew is intended to provide deep pretty printing
|
|
||||||
capabilities on structures, it intentionally does not return any errors.
|
|
||||||
*/
|
|
||||||
package spew
|
|
509
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
509
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
@ -1,509 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// uint8Type is a reflect.Type representing a uint8. It is used to
|
|
||||||
// convert cgo types to uint8 slices for hexdumping.
|
|
||||||
uint8Type = reflect.TypeOf(uint8(0))
|
|
||||||
|
|
||||||
// cCharRE is a regular expression that matches a cgo char.
|
|
||||||
// It is used to detect character arrays to hexdump them.
|
|
||||||
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
|
|
||||||
|
|
||||||
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
|
||||||
// char. It is used to detect unsigned character arrays to hexdump
|
|
||||||
// them.
|
|
||||||
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
|
|
||||||
|
|
||||||
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
|
||||||
// It is used to detect uint8_t arrays to hexdump them.
|
|
||||||
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
|
|
||||||
)
|
|
||||||
|
|
||||||
// dumpState contains information about the state of a dump operation.
|
|
||||||
type dumpState struct {
|
|
||||||
w io.Writer
|
|
||||||
depth int
|
|
||||||
pointers map[uintptr]int
|
|
||||||
ignoreNextType bool
|
|
||||||
ignoreNextIndent bool
|
|
||||||
cs *ConfigState
|
|
||||||
}
|
|
||||||
|
|
||||||
// indent performs indentation according to the depth level and cs.Indent
|
|
||||||
// option.
|
|
||||||
func (d *dumpState) indent() {
|
|
||||||
if d.ignoreNextIndent {
|
|
||||||
d.ignoreNextIndent = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
|
|
||||||
}
|
|
||||||
|
|
||||||
// unpackValue returns values inside of non-nil interfaces when possible.
|
|
||||||
// This is useful for data types like structs, arrays, slices, and maps which
|
|
||||||
// can contain varying types packed inside an interface.
|
|
||||||
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
|
|
||||||
if v.Kind() == reflect.Interface && !v.IsNil() {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// dumpPtr handles formatting of pointers by indirecting them as necessary.
|
|
||||||
func (d *dumpState) dumpPtr(v reflect.Value) {
|
|
||||||
// Remove pointers at or below the current depth from map used to detect
|
|
||||||
// circular refs.
|
|
||||||
for k, depth := range d.pointers {
|
|
||||||
if depth >= d.depth {
|
|
||||||
delete(d.pointers, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep list of all dereferenced pointers to show later.
|
|
||||||
pointerChain := make([]uintptr, 0)
|
|
||||||
|
|
||||||
// Figure out how many levels of indirection there are by dereferencing
|
|
||||||
// pointers and unpacking interfaces down the chain while detecting circular
|
|
||||||
// references.
|
|
||||||
nilFound := false
|
|
||||||
cycleFound := false
|
|
||||||
indirects := 0
|
|
||||||
ve := v
|
|
||||||
for ve.Kind() == reflect.Ptr {
|
|
||||||
if ve.IsNil() {
|
|
||||||
nilFound = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
indirects++
|
|
||||||
addr := ve.Pointer()
|
|
||||||
pointerChain = append(pointerChain, addr)
|
|
||||||
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
|
|
||||||
cycleFound = true
|
|
||||||
indirects--
|
|
||||||
break
|
|
||||||
}
|
|
||||||
d.pointers[addr] = d.depth
|
|
||||||
|
|
||||||
ve = ve.Elem()
|
|
||||||
if ve.Kind() == reflect.Interface {
|
|
||||||
if ve.IsNil() {
|
|
||||||
nilFound = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ve = ve.Elem()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display type information.
|
|
||||||
d.w.Write(openParenBytes)
|
|
||||||
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
|
|
||||||
d.w.Write([]byte(ve.Type().String()))
|
|
||||||
d.w.Write(closeParenBytes)
|
|
||||||
|
|
||||||
// Display pointer information.
|
|
||||||
if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
|
|
||||||
d.w.Write(openParenBytes)
|
|
||||||
for i, addr := range pointerChain {
|
|
||||||
if i > 0 {
|
|
||||||
d.w.Write(pointerChainBytes)
|
|
||||||
}
|
|
||||||
printHexPtr(d.w, addr)
|
|
||||||
}
|
|
||||||
d.w.Write(closeParenBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display dereferenced value.
|
|
||||||
d.w.Write(openParenBytes)
|
|
||||||
switch {
|
|
||||||
case nilFound == true:
|
|
||||||
d.w.Write(nilAngleBytes)
|
|
||||||
|
|
||||||
case cycleFound == true:
|
|
||||||
d.w.Write(circularBytes)
|
|
||||||
|
|
||||||
default:
|
|
||||||
d.ignoreNextType = true
|
|
||||||
d.dump(ve)
|
|
||||||
}
|
|
||||||
d.w.Write(closeParenBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
|
|
||||||
// reflection) arrays and slices are dumped in hexdump -C fashion.
|
|
||||||
func (d *dumpState) dumpSlice(v reflect.Value) {
|
|
||||||
// Determine whether this type should be hex dumped or not. Also,
|
|
||||||
// for types which should be hexdumped, try to use the underlying data
|
|
||||||
// first, then fall back to trying to convert them to a uint8 slice.
|
|
||||||
var buf []uint8
|
|
||||||
doConvert := false
|
|
||||||
doHexDump := false
|
|
||||||
numEntries := v.Len()
|
|
||||||
if numEntries > 0 {
|
|
||||||
vt := v.Index(0).Type()
|
|
||||||
vts := vt.String()
|
|
||||||
switch {
|
|
||||||
// C types that need to be converted.
|
|
||||||
case cCharRE.MatchString(vts):
|
|
||||||
fallthrough
|
|
||||||
case cUnsignedCharRE.MatchString(vts):
|
|
||||||
fallthrough
|
|
||||||
case cUint8tCharRE.MatchString(vts):
|
|
||||||
doConvert = true
|
|
||||||
|
|
||||||
// Try to use existing uint8 slices and fall back to converting
|
|
||||||
// and copying if that fails.
|
|
||||||
case vt.Kind() == reflect.Uint8:
|
|
||||||
// We need an addressable interface to convert the type
|
|
||||||
// to a byte slice. However, the reflect package won't
|
|
||||||
// give us an interface on certain things like
|
|
||||||
// unexported struct fields in order to enforce
|
|
||||||
// visibility rules. We use unsafe, when available, to
|
|
||||||
// bypass these restrictions since this package does not
|
|
||||||
// mutate the values.
|
|
||||||
vs := v
|
|
||||||
if !vs.CanInterface() || !vs.CanAddr() {
|
|
||||||
vs = unsafeReflectValue(vs)
|
|
||||||
}
|
|
||||||
if !UnsafeDisabled {
|
|
||||||
vs = vs.Slice(0, numEntries)
|
|
||||||
|
|
||||||
// Use the existing uint8 slice if it can be
|
|
||||||
// type asserted.
|
|
||||||
iface := vs.Interface()
|
|
||||||
if slice, ok := iface.([]uint8); ok {
|
|
||||||
buf = slice
|
|
||||||
doHexDump = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The underlying data needs to be converted if it can't
|
|
||||||
// be type asserted to a uint8 slice.
|
|
||||||
doConvert = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy and convert the underlying type if needed.
|
|
||||||
if doConvert && vt.ConvertibleTo(uint8Type) {
|
|
||||||
// Convert and copy each element into a uint8 byte
|
|
||||||
// slice.
|
|
||||||
buf = make([]uint8, numEntries)
|
|
||||||
for i := 0; i < numEntries; i++ {
|
|
||||||
vv := v.Index(i)
|
|
||||||
buf[i] = uint8(vv.Convert(uint8Type).Uint())
|
|
||||||
}
|
|
||||||
doHexDump = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hexdump the entire slice as needed.
|
|
||||||
if doHexDump {
|
|
||||||
indent := strings.Repeat(d.cs.Indent, d.depth)
|
|
||||||
str := indent + hex.Dump(buf)
|
|
||||||
str = strings.Replace(str, "\n", "\n"+indent, -1)
|
|
||||||
str = strings.TrimRight(str, d.cs.Indent)
|
|
||||||
d.w.Write([]byte(str))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursively call dump for each item.
|
|
||||||
for i := 0; i < numEntries; i++ {
|
|
||||||
d.dump(d.unpackValue(v.Index(i)))
|
|
||||||
if i < (numEntries - 1) {
|
|
||||||
d.w.Write(commaNewlineBytes)
|
|
||||||
} else {
|
|
||||||
d.w.Write(newlineBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
|
||||||
// value to figure out what kind of object we are dealing with and formats it
|
|
||||||
// appropriately. It is a recursive function, however circular data structures
|
|
||||||
// are detected and handled properly.
|
|
||||||
func (d *dumpState) dump(v reflect.Value) {
|
|
||||||
// Handle invalid reflect values immediately.
|
|
||||||
kind := v.Kind()
|
|
||||||
if kind == reflect.Invalid {
|
|
||||||
d.w.Write(invalidAngleBytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle pointers specially.
|
|
||||||
if kind == reflect.Ptr {
|
|
||||||
d.indent()
|
|
||||||
d.dumpPtr(v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print type information unless already handled elsewhere.
|
|
||||||
if !d.ignoreNextType {
|
|
||||||
d.indent()
|
|
||||||
d.w.Write(openParenBytes)
|
|
||||||
d.w.Write([]byte(v.Type().String()))
|
|
||||||
d.w.Write(closeParenBytes)
|
|
||||||
d.w.Write(spaceBytes)
|
|
||||||
}
|
|
||||||
d.ignoreNextType = false
|
|
||||||
|
|
||||||
// Display length and capacity if the built-in len and cap functions
|
|
||||||
// work with the value's kind and the len/cap itself is non-zero.
|
|
||||||
valueLen, valueCap := 0, 0
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.Array, reflect.Slice, reflect.Chan:
|
|
||||||
valueLen, valueCap = v.Len(), v.Cap()
|
|
||||||
case reflect.Map, reflect.String:
|
|
||||||
valueLen = v.Len()
|
|
||||||
}
|
|
||||||
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
|
|
||||||
d.w.Write(openParenBytes)
|
|
||||||
if valueLen != 0 {
|
|
||||||
d.w.Write(lenEqualsBytes)
|
|
||||||
printInt(d.w, int64(valueLen), 10)
|
|
||||||
}
|
|
||||||
if !d.cs.DisableCapacities && valueCap != 0 {
|
|
||||||
if valueLen != 0 {
|
|
||||||
d.w.Write(spaceBytes)
|
|
||||||
}
|
|
||||||
d.w.Write(capEqualsBytes)
|
|
||||||
printInt(d.w, int64(valueCap), 10)
|
|
||||||
}
|
|
||||||
d.w.Write(closeParenBytes)
|
|
||||||
d.w.Write(spaceBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call Stringer/error interfaces if they exist and the handle methods flag
|
|
||||||
// is enabled
|
|
||||||
if !d.cs.DisableMethods {
|
|
||||||
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
|
||||||
if handled := handleMethods(d.cs, d.w, v); handled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch kind {
|
|
||||||
case reflect.Invalid:
|
|
||||||
// Do nothing. We should never get here since invalid has already
|
|
||||||
// been handled above.
|
|
||||||
|
|
||||||
case reflect.Bool:
|
|
||||||
printBool(d.w, v.Bool())
|
|
||||||
|
|
||||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
|
||||||
printInt(d.w, v.Int(), 10)
|
|
||||||
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
|
||||||
printUint(d.w, v.Uint(), 10)
|
|
||||||
|
|
||||||
case reflect.Float32:
|
|
||||||
printFloat(d.w, v.Float(), 32)
|
|
||||||
|
|
||||||
case reflect.Float64:
|
|
||||||
printFloat(d.w, v.Float(), 64)
|
|
||||||
|
|
||||||
case reflect.Complex64:
|
|
||||||
printComplex(d.w, v.Complex(), 32)
|
|
||||||
|
|
||||||
case reflect.Complex128:
|
|
||||||
printComplex(d.w, v.Complex(), 64)
|
|
||||||
|
|
||||||
case reflect.Slice:
|
|
||||||
if v.IsNil() {
|
|
||||||
d.w.Write(nilAngleBytes)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case reflect.Array:
|
|
||||||
d.w.Write(openBraceNewlineBytes)
|
|
||||||
d.depth++
|
|
||||||
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
|
||||||
d.indent()
|
|
||||||
d.w.Write(maxNewlineBytes)
|
|
||||||
} else {
|
|
||||||
d.dumpSlice(v)
|
|
||||||
}
|
|
||||||
d.depth--
|
|
||||||
d.indent()
|
|
||||||
d.w.Write(closeBraceBytes)
|
|
||||||
|
|
||||||
case reflect.String:
|
|
||||||
d.w.Write([]byte(strconv.Quote(v.String())))
|
|
||||||
|
|
||||||
case reflect.Interface:
|
|
||||||
// The only time we should get here is for nil interfaces due to
|
|
||||||
// unpackValue calls.
|
|
||||||
if v.IsNil() {
|
|
||||||
d.w.Write(nilAngleBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
case reflect.Ptr:
|
|
||||||
// Do nothing. We should never get here since pointers have already
|
|
||||||
// been handled above.
|
|
||||||
|
|
||||||
case reflect.Map:
|
|
||||||
// nil maps should be indicated as different than empty maps
|
|
||||||
if v.IsNil() {
|
|
||||||
d.w.Write(nilAngleBytes)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
d.w.Write(openBraceNewlineBytes)
|
|
||||||
d.depth++
|
|
||||||
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
|
||||||
d.indent()
|
|
||||||
d.w.Write(maxNewlineBytes)
|
|
||||||
} else {
|
|
||||||
numEntries := v.Len()
|
|
||||||
keys := v.MapKeys()
|
|
||||||
if d.cs.SortKeys {
|
|
||||||
sortValues(keys, d.cs)
|
|
||||||
}
|
|
||||||
for i, key := range keys {
|
|
||||||
d.dump(d.unpackValue(key))
|
|
||||||
d.w.Write(colonSpaceBytes)
|
|
||||||
d.ignoreNextIndent = true
|
|
||||||
d.dump(d.unpackValue(v.MapIndex(key)))
|
|
||||||
if i < (numEntries - 1) {
|
|
||||||
d.w.Write(commaNewlineBytes)
|
|
||||||
} else {
|
|
||||||
d.w.Write(newlineBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.depth--
|
|
||||||
d.indent()
|
|
||||||
d.w.Write(closeBraceBytes)
|
|
||||||
|
|
||||||
case reflect.Struct:
|
|
||||||
d.w.Write(openBraceNewlineBytes)
|
|
||||||
d.depth++
|
|
||||||
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
|
||||||
d.indent()
|
|
||||||
d.w.Write(maxNewlineBytes)
|
|
||||||
} else {
|
|
||||||
vt := v.Type()
|
|
||||||
numFields := v.NumField()
|
|
||||||
for i := 0; i < numFields; i++ {
|
|
||||||
d.indent()
|
|
||||||
vtf := vt.Field(i)
|
|
||||||
d.w.Write([]byte(vtf.Name))
|
|
||||||
d.w.Write(colonSpaceBytes)
|
|
||||||
d.ignoreNextIndent = true
|
|
||||||
d.dump(d.unpackValue(v.Field(i)))
|
|
||||||
if i < (numFields - 1) {
|
|
||||||
d.w.Write(commaNewlineBytes)
|
|
||||||
} else {
|
|
||||||
d.w.Write(newlineBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d.depth--
|
|
||||||
d.indent()
|
|
||||||
d.w.Write(closeBraceBytes)
|
|
||||||
|
|
||||||
case reflect.Uintptr:
|
|
||||||
printHexPtr(d.w, uintptr(v.Uint()))
|
|
||||||
|
|
||||||
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
|
||||||
printHexPtr(d.w, v.Pointer())
|
|
||||||
|
|
||||||
// There were not any other types at the time this code was written, but
|
|
||||||
// fall back to letting the default fmt package handle it in case any new
|
|
||||||
// types are added.
|
|
||||||
default:
|
|
||||||
if v.CanInterface() {
|
|
||||||
fmt.Fprintf(d.w, "%v", v.Interface())
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(d.w, "%v", v.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fdump is a helper function to consolidate the logic from the various public
|
|
||||||
// methods which take varying writers and config states.
|
|
||||||
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
|
|
||||||
for _, arg := range a {
|
|
||||||
if arg == nil {
|
|
||||||
w.Write(interfaceBytes)
|
|
||||||
w.Write(spaceBytes)
|
|
||||||
w.Write(nilAngleBytes)
|
|
||||||
w.Write(newlineBytes)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
d := dumpState{w: w, cs: cs}
|
|
||||||
d.pointers = make(map[uintptr]int)
|
|
||||||
d.dump(reflect.ValueOf(arg))
|
|
||||||
d.w.Write(newlineBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
|
||||||
// exactly the same as Dump.
|
|
||||||
func Fdump(w io.Writer, a ...interface{}) {
|
|
||||||
fdump(&Config, w, a...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sdump returns a string with the passed arguments formatted exactly the same
|
|
||||||
// as Dump.
|
|
||||||
func Sdump(a ...interface{}) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
fdump(&Config, &buf, a...)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Dump displays the passed parameters to standard out with newlines, customizable
|
|
||||||
indentation, and additional debug information such as complete types and all
|
|
||||||
pointer addresses used to indirect to the final value. It provides the
|
|
||||||
following features over the built-in printing facilities provided by the fmt
|
|
||||||
package:
|
|
||||||
|
|
||||||
* Pointers are dereferenced and followed
|
|
||||||
* Circular data structures are detected and handled properly
|
|
||||||
* Custom Stringer/error interfaces are optionally invoked, including
|
|
||||||
on unexported types
|
|
||||||
* Custom types which only implement the Stringer/error interfaces via
|
|
||||||
a pointer receiver are optionally invoked when passing non-pointer
|
|
||||||
variables
|
|
||||||
* Byte arrays and slices are dumped like the hexdump -C command which
|
|
||||||
includes offsets, byte values in hex, and ASCII output
|
|
||||||
|
|
||||||
The configuration options are controlled by an exported package global,
|
|
||||||
spew.Config. See ConfigState for options documentation.
|
|
||||||
|
|
||||||
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
|
||||||
get the formatted result as a string.
|
|
||||||
*/
|
|
||||||
func Dump(a ...interface{}) {
|
|
||||||
fdump(&Config, os.Stdout, a...)
|
|
||||||
}
|
|
419
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
419
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
@ -1,419 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// supportedFlags is a list of all the character flags supported by fmt package.
|
|
||||||
const supportedFlags = "0-+# "
|
|
||||||
|
|
||||||
// formatState implements the fmt.Formatter interface and contains information
|
|
||||||
// about the state of a formatting operation. The NewFormatter function can
|
|
||||||
// be used to get a new Formatter which can be used directly as arguments
|
|
||||||
// in standard fmt package printing calls.
|
|
||||||
type formatState struct {
|
|
||||||
value interface{}
|
|
||||||
fs fmt.State
|
|
||||||
depth int
|
|
||||||
pointers map[uintptr]int
|
|
||||||
ignoreNextType bool
|
|
||||||
cs *ConfigState
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildDefaultFormat recreates the original format string without precision
|
|
||||||
// and width information to pass in to fmt.Sprintf in the case of an
|
|
||||||
// unrecognized type. Unless new types are added to the language, this
|
|
||||||
// function won't ever be called.
|
|
||||||
func (f *formatState) buildDefaultFormat() (format string) {
|
|
||||||
buf := bytes.NewBuffer(percentBytes)
|
|
||||||
|
|
||||||
for _, flag := range supportedFlags {
|
|
||||||
if f.fs.Flag(int(flag)) {
|
|
||||||
buf.WriteRune(flag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteRune('v')
|
|
||||||
|
|
||||||
format = buf.String()
|
|
||||||
return format
|
|
||||||
}
|
|
||||||
|
|
||||||
// constructOrigFormat recreates the original format string including precision
|
|
||||||
// and width information to pass along to the standard fmt package. This allows
|
|
||||||
// automatic deferral of all format strings this package doesn't support.
|
|
||||||
func (f *formatState) constructOrigFormat(verb rune) (format string) {
|
|
||||||
buf := bytes.NewBuffer(percentBytes)
|
|
||||||
|
|
||||||
for _, flag := range supportedFlags {
|
|
||||||
if f.fs.Flag(int(flag)) {
|
|
||||||
buf.WriteRune(flag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if width, ok := f.fs.Width(); ok {
|
|
||||||
buf.WriteString(strconv.Itoa(width))
|
|
||||||
}
|
|
||||||
|
|
||||||
if precision, ok := f.fs.Precision(); ok {
|
|
||||||
buf.Write(precisionBytes)
|
|
||||||
buf.WriteString(strconv.Itoa(precision))
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteRune(verb)
|
|
||||||
|
|
||||||
format = buf.String()
|
|
||||||
return format
|
|
||||||
}
|
|
||||||
|
|
||||||
// unpackValue returns values inside of non-nil interfaces when possible and
|
|
||||||
// ensures that types for values which have been unpacked from an interface
|
|
||||||
// are displayed when the show types flag is also set.
|
|
||||||
// This is useful for data types like structs, arrays, slices, and maps which
|
|
||||||
// can contain varying types packed inside an interface.
|
|
||||||
func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
|
|
||||||
if v.Kind() == reflect.Interface {
|
|
||||||
f.ignoreNextType = false
|
|
||||||
if !v.IsNil() {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatPtr handles formatting of pointers by indirecting them as necessary.
|
|
||||||
func (f *formatState) formatPtr(v reflect.Value) {
|
|
||||||
// Display nil if top level pointer is nil.
|
|
||||||
showTypes := f.fs.Flag('#')
|
|
||||||
if v.IsNil() && (!showTypes || f.ignoreNextType) {
|
|
||||||
f.fs.Write(nilAngleBytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove pointers at or below the current depth from map used to detect
|
|
||||||
// circular refs.
|
|
||||||
for k, depth := range f.pointers {
|
|
||||||
if depth >= f.depth {
|
|
||||||
delete(f.pointers, k)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep list of all dereferenced pointers to possibly show later.
|
|
||||||
pointerChain := make([]uintptr, 0)
|
|
||||||
|
|
||||||
// Figure out how many levels of indirection there are by derferencing
|
|
||||||
// pointers and unpacking interfaces down the chain while detecting circular
|
|
||||||
// references.
|
|
||||||
nilFound := false
|
|
||||||
cycleFound := false
|
|
||||||
indirects := 0
|
|
||||||
ve := v
|
|
||||||
for ve.Kind() == reflect.Ptr {
|
|
||||||
if ve.IsNil() {
|
|
||||||
nilFound = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
indirects++
|
|
||||||
addr := ve.Pointer()
|
|
||||||
pointerChain = append(pointerChain, addr)
|
|
||||||
if pd, ok := f.pointers[addr]; ok && pd < f.depth {
|
|
||||||
cycleFound = true
|
|
||||||
indirects--
|
|
||||||
break
|
|
||||||
}
|
|
||||||
f.pointers[addr] = f.depth
|
|
||||||
|
|
||||||
ve = ve.Elem()
|
|
||||||
if ve.Kind() == reflect.Interface {
|
|
||||||
if ve.IsNil() {
|
|
||||||
nilFound = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
ve = ve.Elem()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display type or indirection level depending on flags.
|
|
||||||
if showTypes && !f.ignoreNextType {
|
|
||||||
f.fs.Write(openParenBytes)
|
|
||||||
f.fs.Write(bytes.Repeat(asteriskBytes, indirects))
|
|
||||||
f.fs.Write([]byte(ve.Type().String()))
|
|
||||||
f.fs.Write(closeParenBytes)
|
|
||||||
} else {
|
|
||||||
if nilFound || cycleFound {
|
|
||||||
indirects += strings.Count(ve.Type().String(), "*")
|
|
||||||
}
|
|
||||||
f.fs.Write(openAngleBytes)
|
|
||||||
f.fs.Write([]byte(strings.Repeat("*", indirects)))
|
|
||||||
f.fs.Write(closeAngleBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display pointer information depending on flags.
|
|
||||||
if f.fs.Flag('+') && (len(pointerChain) > 0) {
|
|
||||||
f.fs.Write(openParenBytes)
|
|
||||||
for i, addr := range pointerChain {
|
|
||||||
if i > 0 {
|
|
||||||
f.fs.Write(pointerChainBytes)
|
|
||||||
}
|
|
||||||
printHexPtr(f.fs, addr)
|
|
||||||
}
|
|
||||||
f.fs.Write(closeParenBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display dereferenced value.
|
|
||||||
switch {
|
|
||||||
case nilFound == true:
|
|
||||||
f.fs.Write(nilAngleBytes)
|
|
||||||
|
|
||||||
case cycleFound == true:
|
|
||||||
f.fs.Write(circularShortBytes)
|
|
||||||
|
|
||||||
default:
|
|
||||||
f.ignoreNextType = true
|
|
||||||
f.format(ve)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// format is the main workhorse for providing the Formatter interface. It
|
|
||||||
// uses the passed reflect value to figure out what kind of object we are
|
|
||||||
// dealing with and formats it appropriately. It is a recursive function,
|
|
||||||
// however circular data structures are detected and handled properly.
|
|
||||||
func (f *formatState) format(v reflect.Value) {
|
|
||||||
// Handle invalid reflect values immediately.
|
|
||||||
kind := v.Kind()
|
|
||||||
if kind == reflect.Invalid {
|
|
||||||
f.fs.Write(invalidAngleBytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle pointers specially.
|
|
||||||
if kind == reflect.Ptr {
|
|
||||||
f.formatPtr(v)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print type information unless already handled elsewhere.
|
|
||||||
if !f.ignoreNextType && f.fs.Flag('#') {
|
|
||||||
f.fs.Write(openParenBytes)
|
|
||||||
f.fs.Write([]byte(v.Type().String()))
|
|
||||||
f.fs.Write(closeParenBytes)
|
|
||||||
}
|
|
||||||
f.ignoreNextType = false
|
|
||||||
|
|
||||||
// Call Stringer/error interfaces if they exist and the handle methods
|
|
||||||
// flag is enabled.
|
|
||||||
if !f.cs.DisableMethods {
|
|
||||||
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
|
||||||
if handled := handleMethods(f.cs, f.fs, v); handled {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch kind {
|
|
||||||
case reflect.Invalid:
|
|
||||||
// Do nothing. We should never get here since invalid has already
|
|
||||||
// been handled above.
|
|
||||||
|
|
||||||
case reflect.Bool:
|
|
||||||
printBool(f.fs, v.Bool())
|
|
||||||
|
|
||||||
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
|
||||||
printInt(f.fs, v.Int(), 10)
|
|
||||||
|
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
|
||||||
printUint(f.fs, v.Uint(), 10)
|
|
||||||
|
|
||||||
case reflect.Float32:
|
|
||||||
printFloat(f.fs, v.Float(), 32)
|
|
||||||
|
|
||||||
case reflect.Float64:
|
|
||||||
printFloat(f.fs, v.Float(), 64)
|
|
||||||
|
|
||||||
case reflect.Complex64:
|
|
||||||
printComplex(f.fs, v.Complex(), 32)
|
|
||||||
|
|
||||||
case reflect.Complex128:
|
|
||||||
printComplex(f.fs, v.Complex(), 64)
|
|
||||||
|
|
||||||
case reflect.Slice:
|
|
||||||
if v.IsNil() {
|
|
||||||
f.fs.Write(nilAngleBytes)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
|
|
||||||
case reflect.Array:
|
|
||||||
f.fs.Write(openBracketBytes)
|
|
||||||
f.depth++
|
|
||||||
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
|
||||||
f.fs.Write(maxShortBytes)
|
|
||||||
} else {
|
|
||||||
numEntries := v.Len()
|
|
||||||
for i := 0; i < numEntries; i++ {
|
|
||||||
if i > 0 {
|
|
||||||
f.fs.Write(spaceBytes)
|
|
||||||
}
|
|
||||||
f.ignoreNextType = true
|
|
||||||
f.format(f.unpackValue(v.Index(i)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.depth--
|
|
||||||
f.fs.Write(closeBracketBytes)
|
|
||||||
|
|
||||||
case reflect.String:
|
|
||||||
f.fs.Write([]byte(v.String()))
|
|
||||||
|
|
||||||
case reflect.Interface:
|
|
||||||
// The only time we should get here is for nil interfaces due to
|
|
||||||
// unpackValue calls.
|
|
||||||
if v.IsNil() {
|
|
||||||
f.fs.Write(nilAngleBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
case reflect.Ptr:
|
|
||||||
// Do nothing. We should never get here since pointers have already
|
|
||||||
// been handled above.
|
|
||||||
|
|
||||||
case reflect.Map:
|
|
||||||
// nil maps should be indicated as different than empty maps
|
|
||||||
if v.IsNil() {
|
|
||||||
f.fs.Write(nilAngleBytes)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
f.fs.Write(openMapBytes)
|
|
||||||
f.depth++
|
|
||||||
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
|
||||||
f.fs.Write(maxShortBytes)
|
|
||||||
} else {
|
|
||||||
keys := v.MapKeys()
|
|
||||||
if f.cs.SortKeys {
|
|
||||||
sortValues(keys, f.cs)
|
|
||||||
}
|
|
||||||
for i, key := range keys {
|
|
||||||
if i > 0 {
|
|
||||||
f.fs.Write(spaceBytes)
|
|
||||||
}
|
|
||||||
f.ignoreNextType = true
|
|
||||||
f.format(f.unpackValue(key))
|
|
||||||
f.fs.Write(colonBytes)
|
|
||||||
f.ignoreNextType = true
|
|
||||||
f.format(f.unpackValue(v.MapIndex(key)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.depth--
|
|
||||||
f.fs.Write(closeMapBytes)
|
|
||||||
|
|
||||||
case reflect.Struct:
|
|
||||||
numFields := v.NumField()
|
|
||||||
f.fs.Write(openBraceBytes)
|
|
||||||
f.depth++
|
|
||||||
if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) {
|
|
||||||
f.fs.Write(maxShortBytes)
|
|
||||||
} else {
|
|
||||||
vt := v.Type()
|
|
||||||
for i := 0; i < numFields; i++ {
|
|
||||||
if i > 0 {
|
|
||||||
f.fs.Write(spaceBytes)
|
|
||||||
}
|
|
||||||
vtf := vt.Field(i)
|
|
||||||
if f.fs.Flag('+') || f.fs.Flag('#') {
|
|
||||||
f.fs.Write([]byte(vtf.Name))
|
|
||||||
f.fs.Write(colonBytes)
|
|
||||||
}
|
|
||||||
f.format(f.unpackValue(v.Field(i)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.depth--
|
|
||||||
f.fs.Write(closeBraceBytes)
|
|
||||||
|
|
||||||
case reflect.Uintptr:
|
|
||||||
printHexPtr(f.fs, uintptr(v.Uint()))
|
|
||||||
|
|
||||||
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
|
||||||
printHexPtr(f.fs, v.Pointer())
|
|
||||||
|
|
||||||
// There were not any other types at the time this code was written, but
|
|
||||||
// fall back to letting the default fmt package handle it if any get added.
|
|
||||||
default:
|
|
||||||
format := f.buildDefaultFormat()
|
|
||||||
if v.CanInterface() {
|
|
||||||
fmt.Fprintf(f.fs, format, v.Interface())
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(f.fs, format, v.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format satisfies the fmt.Formatter interface. See NewFormatter for usage
|
|
||||||
// details.
|
|
||||||
func (f *formatState) Format(fs fmt.State, verb rune) {
|
|
||||||
f.fs = fs
|
|
||||||
|
|
||||||
// Use standard formatting for verbs that are not v.
|
|
||||||
if verb != 'v' {
|
|
||||||
format := f.constructOrigFormat(verb)
|
|
||||||
fmt.Fprintf(fs, format, f.value)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.value == nil {
|
|
||||||
if fs.Flag('#') {
|
|
||||||
fs.Write(interfaceBytes)
|
|
||||||
}
|
|
||||||
fs.Write(nilAngleBytes)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
f.format(reflect.ValueOf(f.value))
|
|
||||||
}
|
|
||||||
|
|
||||||
// newFormatter is a helper function to consolidate the logic from the various
|
|
||||||
// public methods which take varying config states.
|
|
||||||
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
|
|
||||||
fs := &formatState{value: v, cs: cs}
|
|
||||||
fs.pointers = make(map[uintptr]int)
|
|
||||||
return fs
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
|
||||||
interface. As a result, it integrates cleanly with standard fmt package
|
|
||||||
printing functions. The formatter is useful for inline printing of smaller data
|
|
||||||
types similar to the standard %v format specifier.
|
|
||||||
|
|
||||||
The custom formatter only responds to the %v (most compact), %+v (adds pointer
|
|
||||||
addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb
|
|
||||||
combinations. Any other verbs such as %x and %q will be sent to the the
|
|
||||||
standard fmt package for formatting. In addition, the custom formatter ignores
|
|
||||||
the width and precision arguments (however they will still work on the format
|
|
||||||
specifiers not handled by the custom formatter).
|
|
||||||
|
|
||||||
Typically this function shouldn't be called directly. It is much easier to make
|
|
||||||
use of the custom formatter by calling one of the convenience functions such as
|
|
||||||
Printf, Println, or Fprintf.
|
|
||||||
*/
|
|
||||||
func NewFormatter(v interface{}) fmt.Formatter {
|
|
||||||
return newFormatter(&Config, v)
|
|
||||||
}
|
|
148
vendor/github.com/davecgh/go-spew/spew/spew.go
generated
vendored
148
vendor/github.com/davecgh/go-spew/spew/spew.go
generated
vendored
@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the formatted string as a value that satisfies error. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Errorf(format string, a ...interface{}) (err error) {
|
|
||||||
return fmt.Errorf(format, convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Fprint(w, convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Fprintf(w, format, convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Fprintln(w, convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Print(a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Print(convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Printf(format string, a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Printf(format, convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the number of bytes written and any write error encountered. See
|
|
||||||
// NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Println(a ...interface{}) (n int, err error) {
|
|
||||||
return fmt.Println(convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprint is a wrapper for fmt.Sprint that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the resulting string. See NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Sprint(a ...interface{}) string {
|
|
||||||
return fmt.Sprint(convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were
|
|
||||||
// passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the resulting string. See NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Sprintf(format string, a ...interface{}) string {
|
|
||||||
return fmt.Sprintf(format, convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it
|
|
||||||
// were passed with a default Formatter interface returned by NewFormatter. It
|
|
||||||
// returns the resulting string. See NewFormatter for formatting details.
|
|
||||||
//
|
|
||||||
// This function is shorthand for the following syntax:
|
|
||||||
//
|
|
||||||
// fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b))
|
|
||||||
func Sprintln(a ...interface{}) string {
|
|
||||||
return fmt.Sprintln(convertArgs(a)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertArgs accepts a slice of arguments and returns a slice of the same
|
|
||||||
// length with each argument converted to a default spew Formatter interface.
|
|
||||||
func convertArgs(args []interface{}) (formatters []interface{}) {
|
|
||||||
formatters = make([]interface{}, len(args))
|
|
||||||
for index, arg := range args {
|
|
||||||
formatters[index] = NewFormatter(arg)
|
|
||||||
}
|
|
||||||
return formatters
|
|
||||||
}
|
|
23
vendor/github.com/joho/godotenv/LICENCE
generated
vendored
23
vendor/github.com/joho/godotenv/LICENCE
generated
vendored
@ -1,23 +0,0 @@
|
|||||||
Copyright (c) 2013 John Barton
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
127
vendor/github.com/joho/godotenv/README.md
generated
vendored
127
vendor/github.com/joho/godotenv/README.md
generated
vendored
@ -1,127 +0,0 @@
|
|||||||
# GoDotEnv [![Build Status](https://travis-ci.org/joho/godotenv.svg?branch=master)](https://travis-ci.org/joho/godotenv) [![Build status](https://ci.appveyor.com/api/projects/status/9v40vnfvvgde64u4?svg=true)](https://ci.appveyor.com/project/joho/godotenv)
|
|
||||||
|
|
||||||
A Go (golang) port of the Ruby dotenv project (which loads env vars from a .env file)
|
|
||||||
|
|
||||||
From the original Library:
|
|
||||||
|
|
||||||
> Storing configuration in the environment is one of the tenets of a twelve-factor app. Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
|
|
||||||
>
|
|
||||||
> But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. Dotenv load variables from a .env file into ENV when the environment is bootstrapped.
|
|
||||||
|
|
||||||
It can be used as a library (for loading in env for your own daemons etc) or as a bin command.
|
|
||||||
|
|
||||||
There is test coverage and CI for both linuxish and windows environments, but I make no guarantees about the bin version working on windows.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
As a library
|
|
||||||
|
|
||||||
```shell
|
|
||||||
go get github.com/joho/godotenv
|
|
||||||
```
|
|
||||||
|
|
||||||
or if you want to use it as a bin command
|
|
||||||
```shell
|
|
||||||
go get github.com/joho/godotenv/cmd/godotenv
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Add your application configuration to your `.env` file in the root of your project:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
S3_BUCKET=YOURS3BUCKET
|
|
||||||
SECRET_KEY=YOURSECRETKEYGOESHERE
|
|
||||||
```
|
|
||||||
|
|
||||||
Then in your Go app you can do something like
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/joho/godotenv"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
err := godotenv.Load()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Error loading .env file")
|
|
||||||
}
|
|
||||||
|
|
||||||
s3Bucket := os.Getenv("S3_BUCKET")
|
|
||||||
secretKey := os.Getenv("SECRET_KEY")
|
|
||||||
|
|
||||||
// now do something with s3 or whatever
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're even lazier than that, you can just take advantage of the autoload package which will read in `.env` on import
|
|
||||||
|
|
||||||
```go
|
|
||||||
import _ "github.com/joho/godotenv/autoload"
|
|
||||||
```
|
|
||||||
|
|
||||||
While `.env` in the project root is the default, you don't have to be constrained, both examples below are 100% legit
|
|
||||||
|
|
||||||
```go
|
|
||||||
_ = godotenv.Load("somerandomfile")
|
|
||||||
_ = godotenv.Load("filenumberone.env", "filenumbertwo.env")
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to be really fancy with your env file you can do comments and exports (below is a valid env file)
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# I am a comment and that is OK
|
|
||||||
SOME_VAR=someval
|
|
||||||
FOO=BAR # comments at line end are OK too
|
|
||||||
export BAR=BAZ
|
|
||||||
```
|
|
||||||
|
|
||||||
Or finally you can do YAML(ish) style
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
FOO: bar
|
|
||||||
BAR: baz
|
|
||||||
```
|
|
||||||
|
|
||||||
as a final aside, if you don't want godotenv munging your env you can just get a map back instead
|
|
||||||
|
|
||||||
```go
|
|
||||||
var myEnv map[string]string
|
|
||||||
myEnv, err := godotenv.Read()
|
|
||||||
|
|
||||||
s3Bucket := myEnv["S3_BUCKET"]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Command Mode
|
|
||||||
|
|
||||||
Assuming you've installed the command as above and you've got `$GOPATH/bin` in your `$PATH`
|
|
||||||
|
|
||||||
```
|
|
||||||
godotenv -f /some/path/to/.env some_command with some args
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't specify `-f` it will fall back on the default of loading `.env` in `PWD`
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Contributions are most welcome! The parser itself is pretty stupidly naive and I wouldn't be surprised if it breaks with edge cases.
|
|
||||||
|
|
||||||
*code changes without tests will not be accepted*
|
|
||||||
|
|
||||||
1. Fork it
|
|
||||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
||||||
3. Commit your changes (`git commit -am 'Added some feature'`)
|
|
||||||
4. Push to the branch (`git push origin my-new-feature`)
|
|
||||||
5. Create new Pull Request
|
|
||||||
|
|
||||||
## CI
|
|
||||||
|
|
||||||
Linux: [![wercker status](https://app.wercker.com/status/507594c2ec7e60f19403a568dfea0f78/m "wercker status")](https://app.wercker.com/project/bykey/507594c2ec7e60f19403a568dfea0f78) Windows: [![Build status](https://ci.appveyor.com/api/projects/status/9v40vnfvvgde64u4)](https://ci.appveyor.com/project/joho/godotenv)
|
|
||||||
|
|
||||||
## Who?
|
|
||||||
|
|
||||||
The original library [dotenv](https://github.com/bkeepers/dotenv) was written by [Brandon Keepers](http://opensoul.org/), and this port was done by [John Barton](http://whoisjohnbarton.com) based off the tests/fixtures in the original library.
|
|
15
vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
15
vendor/github.com/joho/godotenv/autoload/autoload.go
generated
vendored
@ -1,15 +0,0 @@
|
|||||||
package autoload
|
|
||||||
|
|
||||||
/*
|
|
||||||
You can just read the .env file on import just by doing
|
|
||||||
|
|
||||||
import _ "github.com/joho/godotenv/autoload"
|
|
||||||
|
|
||||||
And bob's your mother's brother
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "github.com/joho/godotenv"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
godotenv.Load()
|
|
||||||
}
|
|
247
vendor/github.com/joho/godotenv/godotenv.go
generated
vendored
247
vendor/github.com/joho/godotenv/godotenv.go
generated
vendored
@ -1,247 +0,0 @@
|
|||||||
// Package godotenv is a go port of the ruby dotenv library (https://github.com/bkeepers/dotenv)
|
|
||||||
//
|
|
||||||
// Examples/readme can be found on the github page at https://github.com/joho/godotenv
|
|
||||||
//
|
|
||||||
// The TL;DR is that you make a .env file that looks something like
|
|
||||||
//
|
|
||||||
// SOME_ENV_VAR=somevalue
|
|
||||||
//
|
|
||||||
// and then in your go code you can call
|
|
||||||
//
|
|
||||||
// godotenv.Load()
|
|
||||||
//
|
|
||||||
// and all the env vars declared in .env will be avaiable through os.Getenv("SOME_ENV_VAR")
|
|
||||||
package godotenv
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Load will read your env file(s) and load them into ENV for this process.
|
|
||||||
//
|
|
||||||
// Call this function as close as possible to the start of your program (ideally in main)
|
|
||||||
//
|
|
||||||
// If you call Load without any args it will default to loading .env in the current path
|
|
||||||
//
|
|
||||||
// You can otherwise tell it which files to load (there can be more than one) like
|
|
||||||
//
|
|
||||||
// godotenv.Load("fileone", "filetwo")
|
|
||||||
//
|
|
||||||
// It's important to note that it WILL NOT OVERRIDE an env variable that already exists - consider the .env file to set dev vars or sensible defaults
|
|
||||||
func Load(filenames ...string) (err error) {
|
|
||||||
filenames = filenamesOrDefault(filenames)
|
|
||||||
|
|
||||||
for _, filename := range filenames {
|
|
||||||
err = loadFile(filename, false)
|
|
||||||
if err != nil {
|
|
||||||
return // return early on a spazout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overload will read your env file(s) and load them into ENV for this process.
|
|
||||||
//
|
|
||||||
// Call this function as close as possible to the start of your program (ideally in main)
|
|
||||||
//
|
|
||||||
// If you call Overload without any args it will default to loading .env in the current path
|
|
||||||
//
|
|
||||||
// You can otherwise tell it which files to load (there can be more than one) like
|
|
||||||
//
|
|
||||||
// godotenv.Overload("fileone", "filetwo")
|
|
||||||
//
|
|
||||||
// It's important to note this WILL OVERRIDE an env variable that already exists - consider the .env file to forcefilly set all vars.
|
|
||||||
func Overload(filenames ...string) (err error) {
|
|
||||||
filenames = filenamesOrDefault(filenames)
|
|
||||||
|
|
||||||
for _, filename := range filenames {
|
|
||||||
err = loadFile(filename, true)
|
|
||||||
if err != nil {
|
|
||||||
return // return early on a spazout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read all env (with same file loading semantics as Load) but return values as
|
|
||||||
// a map rather than automatically writing values into env
|
|
||||||
func Read(filenames ...string) (envMap map[string]string, err error) {
|
|
||||||
filenames = filenamesOrDefault(filenames)
|
|
||||||
envMap = make(map[string]string)
|
|
||||||
|
|
||||||
for _, filename := range filenames {
|
|
||||||
individualEnvMap, individualErr := readFile(filename)
|
|
||||||
|
|
||||||
if individualErr != nil {
|
|
||||||
err = individualErr
|
|
||||||
return // return early on a spazout
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range individualEnvMap {
|
|
||||||
envMap[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec loads env vars from the specified filenames (empty map falls back to default)
|
|
||||||
// then executes the cmd specified.
|
|
||||||
//
|
|
||||||
// Simply hooks up os.Stdin/err/out to the command and calls Run()
|
|
||||||
//
|
|
||||||
// If you want more fine grained control over your command it's recommended
|
|
||||||
// that you use `Load()` or `Read()` and the `os/exec` package yourself.
|
|
||||||
func Exec(filenames []string, cmd string, cmdArgs []string) error {
|
|
||||||
Load(filenames...)
|
|
||||||
|
|
||||||
command := exec.Command(cmd, cmdArgs...)
|
|
||||||
command.Stdin = os.Stdin
|
|
||||||
command.Stdout = os.Stdout
|
|
||||||
command.Stderr = os.Stderr
|
|
||||||
return command.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func filenamesOrDefault(filenames []string) []string {
|
|
||||||
if len(filenames) == 0 {
|
|
||||||
return []string{".env"}
|
|
||||||
}
|
|
||||||
return filenames
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadFile(filename string, overload bool) error {
|
|
||||||
envMap, err := readFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
currentEnv := map[string]bool{}
|
|
||||||
rawEnv := os.Environ()
|
|
||||||
for _, rawEnvLine := range rawEnv {
|
|
||||||
key := strings.Split(rawEnvLine, "=")[0]
|
|
||||||
currentEnv[key] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range envMap {
|
|
||||||
if !currentEnv[key] || overload {
|
|
||||||
os.Setenv(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFile(filename string) (envMap map[string]string, err error) {
|
|
||||||
file, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
envMap = make(map[string]string)
|
|
||||||
|
|
||||||
var lines []string
|
|
||||||
scanner := bufio.NewScanner(file)
|
|
||||||
for scanner.Scan() {
|
|
||||||
lines = append(lines, scanner.Text())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = scanner.Err(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, fullLine := range lines {
|
|
||||||
if !isIgnoredLine(fullLine) {
|
|
||||||
var key, value string
|
|
||||||
key, value, err = parseLine(fullLine)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
envMap[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseLine(line string) (key string, value string, err error) {
|
|
||||||
if len(line) == 0 {
|
|
||||||
err = errors.New("zero length string")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ditch the comments (but keep quoted hashes)
|
|
||||||
if strings.Contains(line, "#") {
|
|
||||||
segmentsBetweenHashes := strings.Split(line, "#")
|
|
||||||
quotesAreOpen := false
|
|
||||||
var segmentsToKeep []string
|
|
||||||
for _, segment := range segmentsBetweenHashes {
|
|
||||||
if strings.Count(segment, "\"") == 1 || strings.Count(segment, "'") == 1 {
|
|
||||||
if quotesAreOpen {
|
|
||||||
quotesAreOpen = false
|
|
||||||
segmentsToKeep = append(segmentsToKeep, segment)
|
|
||||||
} else {
|
|
||||||
quotesAreOpen = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(segmentsToKeep) == 0 || quotesAreOpen {
|
|
||||||
segmentsToKeep = append(segmentsToKeep, segment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line = strings.Join(segmentsToKeep, "#")
|
|
||||||
}
|
|
||||||
|
|
||||||
// now split key from value
|
|
||||||
splitString := strings.SplitN(line, "=", 2)
|
|
||||||
|
|
||||||
if len(splitString) != 2 {
|
|
||||||
// try yaml mode!
|
|
||||||
splitString = strings.SplitN(line, ":", 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(splitString) != 2 {
|
|
||||||
err = errors.New("Can't separate key from value")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the key
|
|
||||||
key = splitString[0]
|
|
||||||
if strings.HasPrefix(key, "export") {
|
|
||||||
key = strings.TrimPrefix(key, "export")
|
|
||||||
}
|
|
||||||
key = strings.Trim(key, " ")
|
|
||||||
|
|
||||||
// Parse the value
|
|
||||||
value = splitString[1]
|
|
||||||
|
|
||||||
// trim
|
|
||||||
value = strings.Trim(value, " ")
|
|
||||||
|
|
||||||
// check if we've got quoted values
|
|
||||||
if value != "" {
|
|
||||||
first := string(value[0:1])
|
|
||||||
last := string(value[len(value)-1:])
|
|
||||||
if first == last && strings.ContainsAny(first, `"'`) {
|
|
||||||
// pull the quotes off the edges
|
|
||||||
value = strings.Trim(value, `"'`)
|
|
||||||
|
|
||||||
// expand quotes
|
|
||||||
value = strings.Replace(value, `\"`, `"`, -1)
|
|
||||||
// expand newlines
|
|
||||||
value = strings.Replace(value, `\n`, "\n", -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func isIgnoredLine(line string) bool {
|
|
||||||
trimmedLine := strings.Trim(line, " \n\t")
|
|
||||||
return len(trimmedLine) == 0 || strings.HasPrefix(trimmedLine, "#")
|
|
||||||
}
|
|
27
vendor/github.com/pmezard/go-difflib/LICENSE
generated
vendored
27
vendor/github.com/pmezard/go-difflib/LICENSE
generated
vendored
@ -1,27 +0,0 @@
|
|||||||
Copyright (c) 2013, Patrick Mezard
|
|
||||||
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.
|
|
||||||
The names of its contributors may not 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
|
|
||||||
HOLDER 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.
|
|
772
vendor/github.com/pmezard/go-difflib/difflib/difflib.go
generated
vendored
772
vendor/github.com/pmezard/go-difflib/difflib/difflib.go
generated
vendored
@ -1,772 +0,0 @@
|
|||||||
// Package difflib is a partial port of Python difflib module.
|
|
||||||
//
|
|
||||||
// It provides tools to compare sequences of strings and generate textual diffs.
|
|
||||||
//
|
|
||||||
// The following class and functions have been ported:
|
|
||||||
//
|
|
||||||
// - SequenceMatcher
|
|
||||||
//
|
|
||||||
// - unified_diff
|
|
||||||
//
|
|
||||||
// - context_diff
|
|
||||||
//
|
|
||||||
// Getting unified diffs was the main goal of the port. Keep in mind this code
|
|
||||||
// is mostly suitable to output text differences in a human friendly way, there
|
|
||||||
// are no guarantees generated diffs are consumable by patch(1).
|
|
||||||
package difflib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func min(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func max(a, b int) int {
|
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func calculateRatio(matches, length int) float64 {
|
|
||||||
if length > 0 {
|
|
||||||
return 2.0 * float64(matches) / float64(length)
|
|
||||||
}
|
|
||||||
return 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
type Match struct {
|
|
||||||
A int
|
|
||||||
B int
|
|
||||||
Size int
|
|
||||||
}
|
|
||||||
|
|
||||||
type OpCode struct {
|
|
||||||
Tag byte
|
|
||||||
I1 int
|
|
||||||
I2 int
|
|
||||||
J1 int
|
|
||||||
J2 int
|
|
||||||
}
|
|
||||||
|
|
||||||
// SequenceMatcher compares sequence of strings. The basic
|
|
||||||
// algorithm predates, and is a little fancier than, an algorithm
|
|
||||||
// published in the late 1980's by Ratcliff and Obershelp under the
|
|
||||||
// hyperbolic name "gestalt pattern matching". The basic idea is to find
|
|
||||||
// the longest contiguous matching subsequence that contains no "junk"
|
|
||||||
// elements (R-O doesn't address junk). The same idea is then applied
|
|
||||||
// recursively to the pieces of the sequences to the left and to the right
|
|
||||||
// of the matching subsequence. This does not yield minimal edit
|
|
||||||
// sequences, but does tend to yield matches that "look right" to people.
|
|
||||||
//
|
|
||||||
// SequenceMatcher tries to compute a "human-friendly diff" between two
|
|
||||||
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
|
|
||||||
// longest *contiguous* & junk-free matching subsequence. That's what
|
|
||||||
// catches peoples' eyes. The Windows(tm) windiff has another interesting
|
|
||||||
// notion, pairing up elements that appear uniquely in each sequence.
|
|
||||||
// That, and the method here, appear to yield more intuitive difference
|
|
||||||
// reports than does diff. This method appears to be the least vulnerable
|
|
||||||
// to synching up on blocks of "junk lines", though (like blank lines in
|
|
||||||
// ordinary text files, or maybe "<P>" lines in HTML files). That may be
|
|
||||||
// because this is the only method of the 3 that has a *concept* of
|
|
||||||
// "junk" <wink>.
|
|
||||||
//
|
|
||||||
// Timing: Basic R-O is cubic time worst case and quadratic time expected
|
|
||||||
// case. SequenceMatcher is quadratic time for the worst case and has
|
|
||||||
// expected-case behavior dependent in a complicated way on how many
|
|
||||||
// elements the sequences have in common; best case time is linear.
|
|
||||||
type SequenceMatcher struct {
|
|
||||||
a []string
|
|
||||||
b []string
|
|
||||||
b2j map[string][]int
|
|
||||||
IsJunk func(string) bool
|
|
||||||
autoJunk bool
|
|
||||||
bJunk map[string]struct{}
|
|
||||||
matchingBlocks []Match
|
|
||||||
fullBCount map[string]int
|
|
||||||
bPopular map[string]struct{}
|
|
||||||
opCodes []OpCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMatcher(a, b []string) *SequenceMatcher {
|
|
||||||
m := SequenceMatcher{autoJunk: true}
|
|
||||||
m.SetSeqs(a, b)
|
|
||||||
return &m
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMatcherWithJunk(a, b []string, autoJunk bool,
|
|
||||||
isJunk func(string) bool) *SequenceMatcher {
|
|
||||||
|
|
||||||
m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
|
|
||||||
m.SetSeqs(a, b)
|
|
||||||
return &m
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set two sequences to be compared.
|
|
||||||
func (m *SequenceMatcher) SetSeqs(a, b []string) {
|
|
||||||
m.SetSeq1(a)
|
|
||||||
m.SetSeq2(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the first sequence to be compared. The second sequence to be compared is
|
|
||||||
// not changed.
|
|
||||||
//
|
|
||||||
// SequenceMatcher computes and caches detailed information about the second
|
|
||||||
// sequence, so if you want to compare one sequence S against many sequences,
|
|
||||||
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
|
|
||||||
// sequences.
|
|
||||||
//
|
|
||||||
// See also SetSeqs() and SetSeq2().
|
|
||||||
func (m *SequenceMatcher) SetSeq1(a []string) {
|
|
||||||
if &a == &m.a {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.a = a
|
|
||||||
m.matchingBlocks = nil
|
|
||||||
m.opCodes = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the second sequence to be compared. The first sequence to be compared is
|
|
||||||
// not changed.
|
|
||||||
func (m *SequenceMatcher) SetSeq2(b []string) {
|
|
||||||
if &b == &m.b {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m.b = b
|
|
||||||
m.matchingBlocks = nil
|
|
||||||
m.opCodes = nil
|
|
||||||
m.fullBCount = nil
|
|
||||||
m.chainB()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SequenceMatcher) chainB() {
|
|
||||||
// Populate line -> index mapping
|
|
||||||
b2j := map[string][]int{}
|
|
||||||
for i, s := range m.b {
|
|
||||||
indices := b2j[s]
|
|
||||||
indices = append(indices, i)
|
|
||||||
b2j[s] = indices
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge junk elements
|
|
||||||
m.bJunk = map[string]struct{}{}
|
|
||||||
if m.IsJunk != nil {
|
|
||||||
junk := m.bJunk
|
|
||||||
for s, _ := range b2j {
|
|
||||||
if m.IsJunk(s) {
|
|
||||||
junk[s] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for s, _ := range junk {
|
|
||||||
delete(b2j, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Purge remaining popular elements
|
|
||||||
popular := map[string]struct{}{}
|
|
||||||
n := len(m.b)
|
|
||||||
if m.autoJunk && n >= 200 {
|
|
||||||
ntest := n/100 + 1
|
|
||||||
for s, indices := range b2j {
|
|
||||||
if len(indices) > ntest {
|
|
||||||
popular[s] = struct{}{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for s, _ := range popular {
|
|
||||||
delete(b2j, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.bPopular = popular
|
|
||||||
m.b2j = b2j
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SequenceMatcher) isBJunk(s string) bool {
|
|
||||||
_, ok := m.bJunk[s]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
|
|
||||||
//
|
|
||||||
// If IsJunk is not defined:
|
|
||||||
//
|
|
||||||
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
|
|
||||||
// alo <= i <= i+k <= ahi
|
|
||||||
// blo <= j <= j+k <= bhi
|
|
||||||
// and for all (i',j',k') meeting those conditions,
|
|
||||||
// k >= k'
|
|
||||||
// i <= i'
|
|
||||||
// and if i == i', j <= j'
|
|
||||||
//
|
|
||||||
// In other words, of all maximal matching blocks, return one that
|
|
||||||
// starts earliest in a, and of all those maximal matching blocks that
|
|
||||||
// start earliest in a, return the one that starts earliest in b.
|
|
||||||
//
|
|
||||||
// If IsJunk is defined, first the longest matching block is
|
|
||||||
// determined as above, but with the additional restriction that no
|
|
||||||
// junk element appears in the block. Then that block is extended as
|
|
||||||
// far as possible by matching (only) junk elements on both sides. So
|
|
||||||
// the resulting block never matches on junk except as identical junk
|
|
||||||
// happens to be adjacent to an "interesting" match.
|
|
||||||
//
|
|
||||||
// If no blocks match, return (alo, blo, 0).
|
|
||||||
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
|
|
||||||
// CAUTION: stripping common prefix or suffix would be incorrect.
|
|
||||||
// E.g.,
|
|
||||||
// ab
|
|
||||||
// acab
|
|
||||||
// Longest matching block is "ab", but if common prefix is
|
|
||||||
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
|
|
||||||
// strip, so ends up claiming that ab is changed to acab by
|
|
||||||
// inserting "ca" in the middle. That's minimal but unintuitive:
|
|
||||||
// "it's obvious" that someone inserted "ac" at the front.
|
|
||||||
// Windiff ends up at the same place as diff, but by pairing up
|
|
||||||
// the unique 'b's and then matching the first two 'a's.
|
|
||||||
besti, bestj, bestsize := alo, blo, 0
|
|
||||||
|
|
||||||
// find longest junk-free match
|
|
||||||
// during an iteration of the loop, j2len[j] = length of longest
|
|
||||||
// junk-free match ending with a[i-1] and b[j]
|
|
||||||
j2len := map[int]int{}
|
|
||||||
for i := alo; i != ahi; i++ {
|
|
||||||
// look at all instances of a[i] in b; note that because
|
|
||||||
// b2j has no junk keys, the loop is skipped if a[i] is junk
|
|
||||||
newj2len := map[int]int{}
|
|
||||||
for _, j := range m.b2j[m.a[i]] {
|
|
||||||
// a[i] matches b[j]
|
|
||||||
if j < blo {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if j >= bhi {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
k := j2len[j-1] + 1
|
|
||||||
newj2len[j] = k
|
|
||||||
if k > bestsize {
|
|
||||||
besti, bestj, bestsize = i-k+1, j-k+1, k
|
|
||||||
}
|
|
||||||
}
|
|
||||||
j2len = newj2len
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extend the best by non-junk elements on each end. In particular,
|
|
||||||
// "popular" non-junk elements aren't in b2j, which greatly speeds
|
|
||||||
// the inner loop above, but also means "the best" match so far
|
|
||||||
// doesn't contain any junk *or* popular non-junk elements.
|
|
||||||
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
|
|
||||||
m.a[besti-1] == m.b[bestj-1] {
|
|
||||||
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
|
||||||
}
|
|
||||||
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
|
||||||
!m.isBJunk(m.b[bestj+bestsize]) &&
|
|
||||||
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
|
||||||
bestsize += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now that we have a wholly interesting match (albeit possibly
|
|
||||||
// empty!), we may as well suck up the matching junk on each
|
|
||||||
// side of it too. Can't think of a good reason not to, and it
|
|
||||||
// saves post-processing the (possibly considerable) expense of
|
|
||||||
// figuring out what to do with it. In the case of an empty
|
|
||||||
// interesting match, this is clearly the right thing to do,
|
|
||||||
// because no other kind of match is possible in the regions.
|
|
||||||
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
|
|
||||||
m.a[besti-1] == m.b[bestj-1] {
|
|
||||||
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
|
|
||||||
}
|
|
||||||
for besti+bestsize < ahi && bestj+bestsize < bhi &&
|
|
||||||
m.isBJunk(m.b[bestj+bestsize]) &&
|
|
||||||
m.a[besti+bestsize] == m.b[bestj+bestsize] {
|
|
||||||
bestsize += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return Match{A: besti, B: bestj, Size: bestsize}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return list of triples describing matching subsequences.
|
|
||||||
//
|
|
||||||
// Each triple is of the form (i, j, n), and means that
|
|
||||||
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
|
|
||||||
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
|
|
||||||
// adjacent triples in the list, and the second is not the last triple in the
|
|
||||||
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
|
|
||||||
// adjacent equal blocks.
|
|
||||||
//
|
|
||||||
// The last triple is a dummy, (len(a), len(b), 0), and is the only
|
|
||||||
// triple with n==0.
|
|
||||||
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
|
|
||||||
if m.matchingBlocks != nil {
|
|
||||||
return m.matchingBlocks
|
|
||||||
}
|
|
||||||
|
|
||||||
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
|
|
||||||
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
|
|
||||||
match := m.findLongestMatch(alo, ahi, blo, bhi)
|
|
||||||
i, j, k := match.A, match.B, match.Size
|
|
||||||
if match.Size > 0 {
|
|
||||||
if alo < i && blo < j {
|
|
||||||
matched = matchBlocks(alo, i, blo, j, matched)
|
|
||||||
}
|
|
||||||
matched = append(matched, match)
|
|
||||||
if i+k < ahi && j+k < bhi {
|
|
||||||
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matched
|
|
||||||
}
|
|
||||||
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
|
|
||||||
|
|
||||||
// It's possible that we have adjacent equal blocks in the
|
|
||||||
// matching_blocks list now.
|
|
||||||
nonAdjacent := []Match{}
|
|
||||||
i1, j1, k1 := 0, 0, 0
|
|
||||||
for _, b := range matched {
|
|
||||||
// Is this block adjacent to i1, j1, k1?
|
|
||||||
i2, j2, k2 := b.A, b.B, b.Size
|
|
||||||
if i1+k1 == i2 && j1+k1 == j2 {
|
|
||||||
// Yes, so collapse them -- this just increases the length of
|
|
||||||
// the first block by the length of the second, and the first
|
|
||||||
// block so lengthened remains the block to compare against.
|
|
||||||
k1 += k2
|
|
||||||
} else {
|
|
||||||
// Not adjacent. Remember the first block (k1==0 means it's
|
|
||||||
// the dummy we started with), and make the second block the
|
|
||||||
// new block to compare against.
|
|
||||||
if k1 > 0 {
|
|
||||||
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
|
||||||
}
|
|
||||||
i1, j1, k1 = i2, j2, k2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if k1 > 0 {
|
|
||||||
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
|
|
||||||
}
|
|
||||||
|
|
||||||
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
|
|
||||||
m.matchingBlocks = nonAdjacent
|
|
||||||
return m.matchingBlocks
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return list of 5-tuples describing how to turn a into b.
|
|
||||||
//
|
|
||||||
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
|
|
||||||
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
|
|
||||||
// tuple preceding it, and likewise for j1 == the previous j2.
|
|
||||||
//
|
|
||||||
// The tags are characters, with these meanings:
|
|
||||||
//
|
|
||||||
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
|
|
||||||
//
|
|
||||||
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
|
|
||||||
//
|
|
||||||
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
|
|
||||||
//
|
|
||||||
// 'e' (equal): a[i1:i2] == b[j1:j2]
|
|
||||||
func (m *SequenceMatcher) GetOpCodes() []OpCode {
|
|
||||||
if m.opCodes != nil {
|
|
||||||
return m.opCodes
|
|
||||||
}
|
|
||||||
i, j := 0, 0
|
|
||||||
matching := m.GetMatchingBlocks()
|
|
||||||
opCodes := make([]OpCode, 0, len(matching))
|
|
||||||
for _, m := range matching {
|
|
||||||
// invariant: we've pumped out correct diffs to change
|
|
||||||
// a[:i] into b[:j], and the next matching block is
|
|
||||||
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
|
|
||||||
// out a diff to change a[i:ai] into b[j:bj], pump out
|
|
||||||
// the matching block, and move (i,j) beyond the match
|
|
||||||
ai, bj, size := m.A, m.B, m.Size
|
|
||||||
tag := byte(0)
|
|
||||||
if i < ai && j < bj {
|
|
||||||
tag = 'r'
|
|
||||||
} else if i < ai {
|
|
||||||
tag = 'd'
|
|
||||||
} else if j < bj {
|
|
||||||
tag = 'i'
|
|
||||||
}
|
|
||||||
if tag > 0 {
|
|
||||||
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
|
|
||||||
}
|
|
||||||
i, j = ai+size, bj+size
|
|
||||||
// the list of matching blocks is terminated by a
|
|
||||||
// sentinel with size 0
|
|
||||||
if size > 0 {
|
|
||||||
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.opCodes = opCodes
|
|
||||||
return m.opCodes
|
|
||||||
}
|
|
||||||
|
|
||||||
// Isolate change clusters by eliminating ranges with no changes.
|
|
||||||
//
|
|
||||||
// Return a generator of groups with up to n lines of context.
|
|
||||||
// Each group is in the same format as returned by GetOpCodes().
|
|
||||||
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
|
|
||||||
if n < 0 {
|
|
||||||
n = 3
|
|
||||||
}
|
|
||||||
codes := m.GetOpCodes()
|
|
||||||
if len(codes) == 0 {
|
|
||||||
codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
|
|
||||||
}
|
|
||||||
// Fixup leading and trailing groups if they show no changes.
|
|
||||||
if codes[0].Tag == 'e' {
|
|
||||||
c := codes[0]
|
|
||||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
|
||||||
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
|
|
||||||
}
|
|
||||||
if codes[len(codes)-1].Tag == 'e' {
|
|
||||||
c := codes[len(codes)-1]
|
|
||||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
|
||||||
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
|
|
||||||
}
|
|
||||||
nn := n + n
|
|
||||||
groups := [][]OpCode{}
|
|
||||||
group := []OpCode{}
|
|
||||||
for _, c := range codes {
|
|
||||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
|
||||||
// End the current group and start a new one whenever
|
|
||||||
// there is a large range with no changes.
|
|
||||||
if c.Tag == 'e' && i2-i1 > nn {
|
|
||||||
group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
|
|
||||||
j1, min(j2, j1+n)})
|
|
||||||
groups = append(groups, group)
|
|
||||||
group = []OpCode{}
|
|
||||||
i1, j1 = max(i1, i2-n), max(j1, j2-n)
|
|
||||||
}
|
|
||||||
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
|
|
||||||
}
|
|
||||||
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
|
|
||||||
groups = append(groups, group)
|
|
||||||
}
|
|
||||||
return groups
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return a measure of the sequences' similarity (float in [0,1]).
|
|
||||||
//
|
|
||||||
// Where T is the total number of elements in both sequences, and
|
|
||||||
// M is the number of matches, this is 2.0*M / T.
|
|
||||||
// Note that this is 1 if the sequences are identical, and 0 if
|
|
||||||
// they have nothing in common.
|
|
||||||
//
|
|
||||||
// .Ratio() is expensive to compute if you haven't already computed
|
|
||||||
// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
|
|
||||||
// want to try .QuickRatio() or .RealQuickRation() first to get an
|
|
||||||
// upper bound.
|
|
||||||
func (m *SequenceMatcher) Ratio() float64 {
|
|
||||||
matches := 0
|
|
||||||
for _, m := range m.GetMatchingBlocks() {
|
|
||||||
matches += m.Size
|
|
||||||
}
|
|
||||||
return calculateRatio(matches, len(m.a)+len(m.b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return an upper bound on ratio() relatively quickly.
|
|
||||||
//
|
|
||||||
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
|
||||||
// is faster to compute.
|
|
||||||
func (m *SequenceMatcher) QuickRatio() float64 {
|
|
||||||
// viewing a and b as multisets, set matches to the cardinality
|
|
||||||
// of their intersection; this counts the number of matches
|
|
||||||
// without regard to order, so is clearly an upper bound
|
|
||||||
if m.fullBCount == nil {
|
|
||||||
m.fullBCount = map[string]int{}
|
|
||||||
for _, s := range m.b {
|
|
||||||
m.fullBCount[s] = m.fullBCount[s] + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// avail[x] is the number of times x appears in 'b' less the
|
|
||||||
// number of times we've seen it in 'a' so far ... kinda
|
|
||||||
avail := map[string]int{}
|
|
||||||
matches := 0
|
|
||||||
for _, s := range m.a {
|
|
||||||
n, ok := avail[s]
|
|
||||||
if !ok {
|
|
||||||
n = m.fullBCount[s]
|
|
||||||
}
|
|
||||||
avail[s] = n - 1
|
|
||||||
if n > 0 {
|
|
||||||
matches += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return calculateRatio(matches, len(m.a)+len(m.b))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return an upper bound on ratio() very quickly.
|
|
||||||
//
|
|
||||||
// This isn't defined beyond that it is an upper bound on .Ratio(), and
|
|
||||||
// is faster to compute than either .Ratio() or .QuickRatio().
|
|
||||||
func (m *SequenceMatcher) RealQuickRatio() float64 {
|
|
||||||
la, lb := len(m.a), len(m.b)
|
|
||||||
return calculateRatio(min(la, lb), la+lb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert range to the "ed" format
|
|
||||||
func formatRangeUnified(start, stop int) string {
|
|
||||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
|
||||||
beginning := start + 1 // lines start numbering with one
|
|
||||||
length := stop - start
|
|
||||||
if length == 1 {
|
|
||||||
return fmt.Sprintf("%d", beginning)
|
|
||||||
}
|
|
||||||
if length == 0 {
|
|
||||||
beginning -= 1 // empty ranges begin at line just before the range
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d,%d", beginning, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unified diff parameters
|
|
||||||
type UnifiedDiff struct {
|
|
||||||
A []string // First sequence lines
|
|
||||||
FromFile string // First file name
|
|
||||||
FromDate string // First file time
|
|
||||||
B []string // Second sequence lines
|
|
||||||
ToFile string // Second file name
|
|
||||||
ToDate string // Second file time
|
|
||||||
Eol string // Headers end of line, defaults to LF
|
|
||||||
Context int // Number of context lines
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare two sequences of lines; generate the delta as a unified diff.
|
|
||||||
//
|
|
||||||
// Unified diffs are a compact way of showing line changes and a few
|
|
||||||
// lines of context. The number of context lines is set by 'n' which
|
|
||||||
// defaults to three.
|
|
||||||
//
|
|
||||||
// By default, the diff control lines (those with ---, +++, or @@) are
|
|
||||||
// created with a trailing newline. This is helpful so that inputs
|
|
||||||
// created from file.readlines() result in diffs that are suitable for
|
|
||||||
// file.writelines() since both the inputs and outputs have trailing
|
|
||||||
// newlines.
|
|
||||||
//
|
|
||||||
// For inputs that do not have trailing newlines, set the lineterm
|
|
||||||
// argument to "" so that the output will be uniformly newline free.
|
|
||||||
//
|
|
||||||
// The unidiff format normally has a header for filenames and modification
|
|
||||||
// times. Any or all of these may be specified using strings for
|
|
||||||
// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
|
|
||||||
// The modification times are normally expressed in the ISO 8601 format.
|
|
||||||
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
|
|
||||||
buf := bufio.NewWriter(writer)
|
|
||||||
defer buf.Flush()
|
|
||||||
wf := func(format string, args ...interface{}) error {
|
|
||||||
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ws := func(s string) error {
|
|
||||||
_, err := buf.WriteString(s)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(diff.Eol) == 0 {
|
|
||||||
diff.Eol = "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
started := false
|
|
||||||
m := NewMatcher(diff.A, diff.B)
|
|
||||||
for _, g := range m.GetGroupedOpCodes(diff.Context) {
|
|
||||||
if !started {
|
|
||||||
started = true
|
|
||||||
fromDate := ""
|
|
||||||
if len(diff.FromDate) > 0 {
|
|
||||||
fromDate = "\t" + diff.FromDate
|
|
||||||
}
|
|
||||||
toDate := ""
|
|
||||||
if len(diff.ToDate) > 0 {
|
|
||||||
toDate = "\t" + diff.ToDate
|
|
||||||
}
|
|
||||||
if diff.FromFile != "" || diff.ToFile != "" {
|
|
||||||
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
first, last := g[0], g[len(g)-1]
|
|
||||||
range1 := formatRangeUnified(first.I1, last.I2)
|
|
||||||
range2 := formatRangeUnified(first.J1, last.J2)
|
|
||||||
if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, c := range g {
|
|
||||||
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
|
|
||||||
if c.Tag == 'e' {
|
|
||||||
for _, line := range diff.A[i1:i2] {
|
|
||||||
if err := ws(" " + line); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if c.Tag == 'r' || c.Tag == 'd' {
|
|
||||||
for _, line := range diff.A[i1:i2] {
|
|
||||||
if err := ws("-" + line); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.Tag == 'r' || c.Tag == 'i' {
|
|
||||||
for _, line := range diff.B[j1:j2] {
|
|
||||||
if err := ws("+" + line); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like WriteUnifiedDiff but returns the diff a string.
|
|
||||||
func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
|
|
||||||
w := &bytes.Buffer{}
|
|
||||||
err := WriteUnifiedDiff(w, diff)
|
|
||||||
return string(w.Bytes()), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert range to the "ed" format.
|
|
||||||
func formatRangeContext(start, stop int) string {
|
|
||||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
|
||||||
beginning := start + 1 // lines start numbering with one
|
|
||||||
length := stop - start
|
|
||||||
if length == 0 {
|
|
||||||
beginning -= 1 // empty ranges begin at line just before the range
|
|
||||||
}
|
|
||||||
if length <= 1 {
|
|
||||||
return fmt.Sprintf("%d", beginning)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContextDiff UnifiedDiff
|
|
||||||
|
|
||||||
// Compare two sequences of lines; generate the delta as a context diff.
|
|
||||||
//
|
|
||||||
// Context diffs are a compact way of showing line changes and a few
|
|
||||||
// lines of context. The number of context lines is set by diff.Context
|
|
||||||
// which defaults to three.
|
|
||||||
//
|
|
||||||
// By default, the diff control lines (those with *** or ---) are
|
|
||||||
// created with a trailing newline.
|
|
||||||
//
|
|
||||||
// For inputs that do not have trailing newlines, set the diff.Eol
|
|
||||||
// argument to "" so that the output will be uniformly newline free.
|
|
||||||
//
|
|
||||||
// The context diff format normally has a header for filenames and
|
|
||||||
// modification times. Any or all of these may be specified using
|
|
||||||
// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
|
|
||||||
// The modification times are normally expressed in the ISO 8601 format.
|
|
||||||
// If not specified, the strings default to blanks.
|
|
||||||
func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
|
|
||||||
buf := bufio.NewWriter(writer)
|
|
||||||
defer buf.Flush()
|
|
||||||
var diffErr error
|
|
||||||
wf := func(format string, args ...interface{}) {
|
|
||||||
_, err := buf.WriteString(fmt.Sprintf(format, args...))
|
|
||||||
if diffErr == nil && err != nil {
|
|
||||||
diffErr = err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ws := func(s string) {
|
|
||||||
_, err := buf.WriteString(s)
|
|
||||||
if diffErr == nil && err != nil {
|
|
||||||
diffErr = err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(diff.Eol) == 0 {
|
|
||||||
diff.Eol = "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix := map[byte]string{
|
|
||||||
'i': "+ ",
|
|
||||||
'd': "- ",
|
|
||||||
'r': "! ",
|
|
||||||
'e': " ",
|
|
||||||
}
|
|
||||||
|
|
||||||
started := false
|
|
||||||
m := NewMatcher(diff.A, diff.B)
|
|
||||||
for _, g := range m.GetGroupedOpCodes(diff.Context) {
|
|
||||||
if !started {
|
|
||||||
started = true
|
|
||||||
fromDate := ""
|
|
||||||
if len(diff.FromDate) > 0 {
|
|
||||||
fromDate = "\t" + diff.FromDate
|
|
||||||
}
|
|
||||||
toDate := ""
|
|
||||||
if len(diff.ToDate) > 0 {
|
|
||||||
toDate = "\t" + diff.ToDate
|
|
||||||
}
|
|
||||||
if diff.FromFile != "" || diff.ToFile != "" {
|
|
||||||
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
|
|
||||||
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
first, last := g[0], g[len(g)-1]
|
|
||||||
ws("***************" + diff.Eol)
|
|
||||||
|
|
||||||
range1 := formatRangeContext(first.I1, last.I2)
|
|
||||||
wf("*** %s ****%s", range1, diff.Eol)
|
|
||||||
for _, c := range g {
|
|
||||||
if c.Tag == 'r' || c.Tag == 'd' {
|
|
||||||
for _, cc := range g {
|
|
||||||
if cc.Tag == 'i' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, line := range diff.A[cc.I1:cc.I2] {
|
|
||||||
ws(prefix[cc.Tag] + line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
range2 := formatRangeContext(first.J1, last.J2)
|
|
||||||
wf("--- %s ----%s", range2, diff.Eol)
|
|
||||||
for _, c := range g {
|
|
||||||
if c.Tag == 'r' || c.Tag == 'i' {
|
|
||||||
for _, cc := range g {
|
|
||||||
if cc.Tag == 'd' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, line := range diff.B[cc.J1:cc.J2] {
|
|
||||||
ws(prefix[cc.Tag] + line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return diffErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like WriteContextDiff but returns the diff a string.
|
|
||||||
func GetContextDiffString(diff ContextDiff) (string, error) {
|
|
||||||
w := &bytes.Buffer{}
|
|
||||||
err := WriteContextDiff(w, diff)
|
|
||||||
return string(w.Bytes()), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split a string on "\n" while preserving them. The output can be used
|
|
||||||
// as input for UnifiedDiff and ContextDiff structures.
|
|
||||||
func SplitLines(s string) []string {
|
|
||||||
lines := strings.SplitAfter(s, "\n")
|
|
||||||
lines[len(lines)-1] += "\n"
|
|
||||||
return lines
|
|
||||||
}
|
|
22
vendor/github.com/stretchr/testify/LICENSE
generated
vendored
22
vendor/github.com/stretchr/testify/LICENSE
generated
vendored
@ -1,22 +0,0 @@
|
|||||||
Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
|
|
||||||
|
|
||||||
Please consider promoting this project if you find it useful.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
|
||||||
obtaining a copy of this software and associated documentation
|
|
||||||
files (the "Software"), to deal in the Software without restriction,
|
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
||||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
||||||
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
||||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
379
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
379
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
@ -1,379 +0,0 @@
|
|||||||
/*
|
|
||||||
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
|
|
||||||
* THIS FILE MUST NOT BE EDITED BY HAND
|
|
||||||
*/
|
|
||||||
|
|
||||||
package assert
|
|
||||||
|
|
||||||
import (
|
|
||||||
http "net/http"
|
|
||||||
url "net/url"
|
|
||||||
time "time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Conditionf uses a Comparison to assert a complex condition.
|
|
||||||
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
|
|
||||||
return Condition(t, comp, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Containsf asserts that the specified string, list(array, slice...) or map contains the
|
|
||||||
// specified substring or element.
|
|
||||||
//
|
|
||||||
// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
|
|
||||||
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
|
|
||||||
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
|
||||||
// a slice or a channel with len == 0.
|
|
||||||
//
|
|
||||||
// assert.Emptyf(t, obj, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Empty(t, object, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equalf asserts that two objects are equal.
|
|
||||||
//
|
|
||||||
// assert.Equalf(t, 123, 123, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
//
|
|
||||||
// Pointer variable equality is determined based on the equality of the
|
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
|
||||||
// cannot be determined and will always fail.
|
|
||||||
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
|
|
||||||
// and that it is equal to the provided error.
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
|
|
||||||
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualValuesf asserts that two objects are equal or convertable to the same types
|
|
||||||
// and equal.
|
|
||||||
//
|
|
||||||
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf asserts that a function returned an error (i.e. not `nil`).
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// if assert.Errorf(t, err, "error message %s", "formatted") {
|
|
||||||
// assert.Equal(t, expectedErrorf, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
|
||||||
return Error(t, err, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exactlyf asserts that two objects are equal is value and type.
|
|
||||||
//
|
|
||||||
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failf reports a failure through
|
|
||||||
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
|
||||||
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FailNowf fails test
|
|
||||||
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
|
||||||
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Falsef asserts that the specified value is false.
|
|
||||||
//
|
|
||||||
// assert.Falsef(t, myBool, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
|
||||||
return False(t, value, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
|
||||||
// body that contains a string.
|
|
||||||
//
|
|
||||||
// assert.HTTPBodyContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
|
|
||||||
return HTTPBodyContains(t, handler, method, url, values, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
|
||||||
// body that does not contain a string.
|
|
||||||
//
|
|
||||||
// assert.HTTPBodyNotContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
|
|
||||||
return HTTPBodyNotContains(t, handler, method, url, values, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPErrorf asserts that a specified handler returns an error status code.
|
|
||||||
//
|
|
||||||
// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
|
||||||
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPError(t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
|
|
||||||
//
|
|
||||||
// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
|
||||||
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPRedirect(t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPSuccessf asserts that a specified handler returns a success status code.
|
|
||||||
//
|
|
||||||
// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPSuccess(t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementsf asserts that an object is implemented by the specified interface.
|
|
||||||
//
|
|
||||||
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
|
||||||
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
|
||||||
//
|
|
||||||
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
|
||||||
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
|
||||||
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
|
||||||
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
|
||||||
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
|
||||||
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
|
||||||
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTypef asserts that the specified objects are of the same type.
|
|
||||||
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONEqf asserts that two JSON strings are equivalent.
|
|
||||||
//
|
|
||||||
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
|
||||||
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lenf asserts that the specified object has specific length.
|
|
||||||
// Lenf also fails if the object has a type that len() not accept.
|
|
||||||
//
|
|
||||||
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
|
|
||||||
return Len(t, object, length, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nilf asserts that the specified object is nil.
|
|
||||||
//
|
|
||||||
// assert.Nilf(t, err, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Nil(t, object, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoErrorf asserts that a function returned no error (i.e. `nil`).
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// if assert.NoErrorf(t, err, "error message %s", "formatted") {
|
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
|
||||||
return NoError(t, err, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
|
|
||||||
// specified substring or element.
|
|
||||||
//
|
|
||||||
// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
|
|
||||||
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
|
|
||||||
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
|
|
||||||
// a slice or a channel with len == 0.
|
|
||||||
//
|
|
||||||
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
|
|
||||||
// assert.Equal(t, "two", obj[1])
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEqualf asserts that the specified values are NOT equal.
|
|
||||||
//
|
|
||||||
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
//
|
|
||||||
// Pointer variable equality is determined based on the equality of the
|
|
||||||
// referenced values (as opposed to the memory addresses).
|
|
||||||
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotNilf asserts that the specified object is not nil.
|
|
||||||
//
|
|
||||||
// assert.NotNilf(t, err, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotNil(t, object, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
|
|
||||||
//
|
|
||||||
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
|
||||||
return NotPanics(t, f, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotRegexpf asserts that a specified regexp does not match a string.
|
|
||||||
//
|
|
||||||
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
|
||||||
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
|
||||||
// elements given in the specified subset(array, slice...).
|
|
||||||
//
|
|
||||||
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotZerof asserts that i is not the zero value for its type and returns the truth.
|
|
||||||
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotZero(t, i, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
|
|
||||||
//
|
|
||||||
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
|
||||||
return Panics(t, f, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
|
|
||||||
// the recovered panic value equals the expected panic value.
|
|
||||||
//
|
|
||||||
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
|
|
||||||
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regexpf asserts that a specified regexp matches a string.
|
|
||||||
//
|
|
||||||
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
|
||||||
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subsetf asserts that the specified list(array, slice...) contains all
|
|
||||||
// elements given in the specified subset(array, slice...).
|
|
||||||
//
|
|
||||||
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truef asserts that the specified value is true.
|
|
||||||
//
|
|
||||||
// assert.Truef(t, myBool, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
|
||||||
return True(t, value, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithinDurationf asserts that the two times are within duration delta of each other.
|
|
||||||
//
|
|
||||||
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
|
|
||||||
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zerof asserts that i is the zero value for its type and returns the truth.
|
|
||||||
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Zero(t, i, append([]interface{}{msg}, args...)...)
|
|
||||||
}
|
|
4
vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
generated
vendored
4
vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
generated
vendored
@ -1,4 +0,0 @@
|
|||||||
{{.CommentFormat}}
|
|
||||||
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
|
|
||||||
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
|
|
||||||
}
|
|
746
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
746
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
@ -1,746 +0,0 @@
|
|||||||
/*
|
|
||||||
* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen
|
|
||||||
* THIS FILE MUST NOT BE EDITED BY HAND
|
|
||||||
*/
|
|
||||||
|
|
||||||
package assert
|
|
||||||
|
|
||||||
import (
|
|
||||||
http "net/http"
|
|
||||||
url "net/url"
|
|
||||||
time "time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Condition uses a Comparison to assert a complex condition.
|
|
||||||
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
|
|
||||||
return Condition(a.t, comp, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conditionf uses a Comparison to assert a complex condition.
|
|
||||||
func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
|
|
||||||
return Conditionf(a.t, comp, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains asserts that the specified string, list(array, slice...) or map contains the
|
|
||||||
// specified substring or element.
|
|
||||||
//
|
|
||||||
// a.Contains("Hello World", "World")
|
|
||||||
// a.Contains(["Hello", "World"], "World")
|
|
||||||
// a.Contains({"Hello": "World"}, "Hello")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Contains(a.t, s, contains, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Containsf asserts that the specified string, list(array, slice...) or map contains the
|
|
||||||
// specified substring or element.
|
|
||||||
//
|
|
||||||
// a.Containsf("Hello World", "World", "error message %s", "formatted")
|
|
||||||
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
|
|
||||||
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Containsf(a.t, s, contains, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
|
||||||
// a slice or a channel with len == 0.
|
|
||||||
//
|
|
||||||
// a.Empty(obj)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Empty(a.t, object, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either
|
|
||||||
// a slice or a channel with len == 0.
|
|
||||||
//
|
|
||||||
// a.Emptyf(obj, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Emptyf(a.t, object, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equal asserts that two objects are equal.
|
|
||||||
//
|
|
||||||
// a.Equal(123, 123)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
//
|
|
||||||
// Pointer variable equality is determined based on the equality of the
|
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
|
||||||
// cannot be determined and will always fail.
|
|
||||||
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Equal(a.t, expected, actual, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualError asserts that a function returned an error (i.e. not `nil`)
|
|
||||||
// and that it is equal to the provided error.
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// a.EqualError(err, expectedErrorString)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
|
|
||||||
return EqualError(a.t, theError, errString, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
|
|
||||||
// and that it is equal to the provided error.
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
|
|
||||||
return EqualErrorf(a.t, theError, errString, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualValues asserts that two objects are equal or convertable to the same types
|
|
||||||
// and equal.
|
|
||||||
//
|
|
||||||
// a.EqualValues(uint32(123), int32(123))
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return EqualValues(a.t, expected, actual, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EqualValuesf asserts that two objects are equal or convertable to the same types
|
|
||||||
// and equal.
|
|
||||||
//
|
|
||||||
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return EqualValuesf(a.t, expected, actual, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equalf asserts that two objects are equal.
|
|
||||||
//
|
|
||||||
// a.Equalf(123, 123, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
//
|
|
||||||
// Pointer variable equality is determined based on the equality of the
|
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
|
||||||
// cannot be determined and will always fail.
|
|
||||||
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Equalf(a.t, expected, actual, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error asserts that a function returned an error (i.e. not `nil`).
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// if a.Error(err) {
|
|
||||||
// assert.Equal(t, expectedError, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
|
|
||||||
return Error(a.t, err, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf asserts that a function returned an error (i.e. not `nil`).
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// if a.Errorf(err, "error message %s", "formatted") {
|
|
||||||
// assert.Equal(t, expectedErrorf, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
|
|
||||||
return Errorf(a.t, err, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exactly asserts that two objects are equal is value and type.
|
|
||||||
//
|
|
||||||
// a.Exactly(int32(123), int64(123))
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Exactly(a.t, expected, actual, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exactlyf asserts that two objects are equal is value and type.
|
|
||||||
//
|
|
||||||
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Exactlyf(a.t, expected, actual, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fail reports a failure through
|
|
||||||
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
|
|
||||||
return Fail(a.t, failureMessage, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FailNow fails test
|
|
||||||
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
|
|
||||||
return FailNow(a.t, failureMessage, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FailNowf fails test
|
|
||||||
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
|
|
||||||
return FailNowf(a.t, failureMessage, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failf reports a failure through
|
|
||||||
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
|
|
||||||
return Failf(a.t, failureMessage, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// False asserts that the specified value is false.
|
|
||||||
//
|
|
||||||
// a.False(myBool)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
|
|
||||||
return False(a.t, value, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Falsef asserts that the specified value is false.
|
|
||||||
//
|
|
||||||
// a.Falsef(myBool, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
|
|
||||||
return Falsef(a.t, value, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyContains asserts that a specified handler returns a
|
|
||||||
// body that contains a string.
|
|
||||||
//
|
|
||||||
// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
|
|
||||||
return HTTPBodyContains(a.t, handler, method, url, values, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
|
||||||
// body that contains a string.
|
|
||||||
//
|
|
||||||
// a.HTTPBodyContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
|
|
||||||
return HTTPBodyContainsf(a.t, handler, method, url, values, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
|
||||||
// body that does not contain a string.
|
|
||||||
//
|
|
||||||
// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
|
|
||||||
return HTTPBodyNotContains(a.t, handler, method, url, values, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
|
||||||
// body that does not contain a string.
|
|
||||||
//
|
|
||||||
// a.HTTPBodyNotContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}) bool {
|
|
||||||
return HTTPBodyNotContainsf(a.t, handler, method, url, values, str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPError asserts that a specified handler returns an error status code.
|
|
||||||
//
|
|
||||||
// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPError(a.t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPErrorf asserts that a specified handler returns an error status code.
|
|
||||||
//
|
|
||||||
// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
|
||||||
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPErrorf(a.t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPRedirect asserts that a specified handler returns a redirect status code.
|
|
||||||
//
|
|
||||||
// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPRedirect(a.t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
|
|
||||||
//
|
|
||||||
// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
|
||||||
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPRedirectf(a.t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPSuccess asserts that a specified handler returns a success status code.
|
|
||||||
//
|
|
||||||
// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPSuccess(a.t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPSuccessf asserts that a specified handler returns a success status code.
|
|
||||||
//
|
|
||||||
// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values) bool {
|
|
||||||
return HTTPSuccessf(a.t, handler, method, url, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements asserts that an object is implemented by the specified interface.
|
|
||||||
//
|
|
||||||
// a.Implements((*MyInterface)(nil), new(MyObject))
|
|
||||||
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Implements(a.t, interfaceObject, object, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementsf asserts that an object is implemented by the specified interface.
|
|
||||||
//
|
|
||||||
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
|
||||||
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Implementsf(a.t, interfaceObject, object, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InDelta asserts that the two numerals are within delta of each other.
|
|
||||||
//
|
|
||||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
|
||||||
return InDelta(a.t, expected, actual, delta, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
|
||||||
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
|
||||||
return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
|
||||||
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
|
||||||
return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
|
||||||
//
|
|
||||||
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
|
||||||
return InDeltaf(a.t, expected, actual, delta, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
|
||||||
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
|
||||||
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
|
||||||
return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
|
||||||
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
|
||||||
return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
|
||||||
return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsType asserts that the specified objects are of the same type.
|
|
||||||
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return IsType(a.t, expectedType, object, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTypef asserts that the specified objects are of the same type.
|
|
||||||
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return IsTypef(a.t, expectedType, object, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONEq asserts that two JSON strings are equivalent.
|
|
||||||
//
|
|
||||||
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
|
||||||
return JSONEq(a.t, expected, actual, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONEqf asserts that two JSON strings are equivalent.
|
|
||||||
//
|
|
||||||
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
|
||||||
return JSONEqf(a.t, expected, actual, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len asserts that the specified object has specific length.
|
|
||||||
// Len also fails if the object has a type that len() not accept.
|
|
||||||
//
|
|
||||||
// a.Len(mySlice, 3)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
|
|
||||||
return Len(a.t, object, length, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lenf asserts that the specified object has specific length.
|
|
||||||
// Lenf also fails if the object has a type that len() not accept.
|
|
||||||
//
|
|
||||||
// a.Lenf(mySlice, 3, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
|
|
||||||
return Lenf(a.t, object, length, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nil asserts that the specified object is nil.
|
|
||||||
//
|
|
||||||
// a.Nil(err)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Nil(a.t, object, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nilf asserts that the specified object is nil.
|
|
||||||
//
|
|
||||||
// a.Nilf(err, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Nilf(a.t, object, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// if a.NoError(err) {
|
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
|
|
||||||
return NoError(a.t, err, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NoErrorf asserts that a function returned no error (i.e. `nil`).
|
|
||||||
//
|
|
||||||
// actualObj, err := SomeFunction()
|
|
||||||
// if a.NoErrorf(err, "error message %s", "formatted") {
|
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
|
|
||||||
return NoErrorf(a.t, err, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
|
||||||
// specified substring or element.
|
|
||||||
//
|
|
||||||
// a.NotContains("Hello World", "Earth")
|
|
||||||
// a.NotContains(["Hello", "World"], "Earth")
|
|
||||||
// a.NotContains({"Hello": "World"}, "Earth")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotContains(a.t, s, contains, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
|
|
||||||
// specified substring or element.
|
|
||||||
//
|
|
||||||
// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
|
|
||||||
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
|
|
||||||
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotContainsf(a.t, s, contains, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
|
|
||||||
// a slice or a channel with len == 0.
|
|
||||||
//
|
|
||||||
// if a.NotEmpty(obj) {
|
|
||||||
// assert.Equal(t, "two", obj[1])
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotEmpty(a.t, object, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either
|
|
||||||
// a slice or a channel with len == 0.
|
|
||||||
//
|
|
||||||
// if a.NotEmptyf(obj, "error message %s", "formatted") {
|
|
||||||
// assert.Equal(t, "two", obj[1])
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotEmptyf(a.t, object, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEqual asserts that the specified values are NOT equal.
|
|
||||||
//
|
|
||||||
// a.NotEqual(obj1, obj2)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
//
|
|
||||||
// Pointer variable equality is determined based on the equality of the
|
|
||||||
// referenced values (as opposed to the memory addresses).
|
|
||||||
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotEqual(a.t, expected, actual, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotEqualf asserts that the specified values are NOT equal.
|
|
||||||
//
|
|
||||||
// a.NotEqualf(obj1, obj2, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
//
|
|
||||||
// Pointer variable equality is determined based on the equality of the
|
|
||||||
// referenced values (as opposed to the memory addresses).
|
|
||||||
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotEqualf(a.t, expected, actual, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotNil asserts that the specified object is not nil.
|
|
||||||
//
|
|
||||||
// a.NotNil(err)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotNil(a.t, object, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotNilf asserts that the specified object is not nil.
|
|
||||||
//
|
|
||||||
// a.NotNilf(err, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotNilf(a.t, object, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
|
|
||||||
//
|
|
||||||
// a.NotPanics(func(){ RemainCalm() })
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotPanics(a.t, f, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
|
|
||||||
//
|
|
||||||
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
|
|
||||||
return NotPanicsf(a.t, f, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotRegexp asserts that a specified regexp does not match a string.
|
|
||||||
//
|
|
||||||
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
|
|
||||||
// a.NotRegexp("^start", "it's not starting")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotRegexp(a.t, rx, str, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotRegexpf asserts that a specified regexp does not match a string.
|
|
||||||
//
|
|
||||||
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
|
||||||
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotRegexpf(a.t, rx, str, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
|
||||||
// elements given in the specified subset(array, slice...).
|
|
||||||
//
|
|
||||||
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotSubset(a.t, list, subset, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
|
||||||
// elements given in the specified subset(array, slice...).
|
|
||||||
//
|
|
||||||
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotSubsetf(a.t, list, subset, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotZero asserts that i is not the zero value for its type and returns the truth.
|
|
||||||
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return NotZero(a.t, i, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotZerof asserts that i is not the zero value for its type and returns the truth.
|
|
||||||
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return NotZerof(a.t, i, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panics asserts that the code inside the specified PanicTestFunc panics.
|
|
||||||
//
|
|
||||||
// a.Panics(func(){ GoCrazy() })
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
|
||||||
return Panics(a.t, f, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
|
|
||||||
// the recovered panic value equals the expected panic value.
|
|
||||||
//
|
|
||||||
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
|
||||||
return PanicsWithValue(a.t, expected, f, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
|
|
||||||
// the recovered panic value equals the expected panic value.
|
|
||||||
//
|
|
||||||
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
|
|
||||||
return PanicsWithValuef(a.t, expected, f, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
|
|
||||||
//
|
|
||||||
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
|
|
||||||
return Panicsf(a.t, f, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regexp asserts that a specified regexp matches a string.
|
|
||||||
//
|
|
||||||
// a.Regexp(regexp.MustCompile("start"), "it's starting")
|
|
||||||
// a.Regexp("start...$", "it's not starting")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Regexp(a.t, rx, str, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regexpf asserts that a specified regexp matches a string.
|
|
||||||
//
|
|
||||||
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
|
||||||
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Regexpf(a.t, rx, str, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subset asserts that the specified list(array, slice...) contains all
|
|
||||||
// elements given in the specified subset(array, slice...).
|
|
||||||
//
|
|
||||||
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Subset(a.t, list, subset, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subsetf asserts that the specified list(array, slice...) contains all
|
|
||||||
// elements given in the specified subset(array, slice...).
|
|
||||||
//
|
|
||||||
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Subsetf(a.t, list, subset, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// True asserts that the specified value is true.
|
|
||||||
//
|
|
||||||
// a.True(myBool)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
|
|
||||||
return True(a.t, value, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Truef asserts that the specified value is true.
|
|
||||||
//
|
|
||||||
// a.Truef(myBool, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
|
|
||||||
return Truef(a.t, value, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithinDuration asserts that the two times are within duration delta of each other.
|
|
||||||
//
|
|
||||||
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
|
|
||||||
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithinDurationf asserts that the two times are within duration delta of each other.
|
|
||||||
//
|
|
||||||
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
|
|
||||||
return WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zero asserts that i is the zero value for its type and returns the truth.
|
|
||||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
|
|
||||||
return Zero(a.t, i, msgAndArgs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zerof asserts that i is the zero value for its type and returns the truth.
|
|
||||||
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
|
|
||||||
return Zerof(a.t, i, msg, args...)
|
|
||||||
}
|
|
4
vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
generated
vendored
4
vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
generated
vendored
@ -1,4 +0,0 @@
|
|||||||
{{.CommentWithoutT "a"}}
|
|
||||||
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
|
|
||||||
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
|
||||||
}
|
|
1208
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
1208
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
File diff suppressed because it is too large
Load Diff
45
vendor/github.com/stretchr/testify/assert/doc.go
generated
vendored
45
vendor/github.com/stretchr/testify/assert/doc.go
generated
vendored
@ -1,45 +0,0 @@
|
|||||||
// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
|
|
||||||
//
|
|
||||||
// Example Usage
|
|
||||||
//
|
|
||||||
// The following is a complete example using assert in a standard test function:
|
|
||||||
// import (
|
|
||||||
// "testing"
|
|
||||||
// "github.com/stretchr/testify/assert"
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// func TestSomething(t *testing.T) {
|
|
||||||
//
|
|
||||||
// var a string = "Hello"
|
|
||||||
// var b string = "Hello"
|
|
||||||
//
|
|
||||||
// assert.Equal(t, a, b, "The two words should be the same.")
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if you assert many times, use the format below:
|
|
||||||
//
|
|
||||||
// import (
|
|
||||||
// "testing"
|
|
||||||
// "github.com/stretchr/testify/assert"
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// func TestSomething(t *testing.T) {
|
|
||||||
// assert := assert.New(t)
|
|
||||||
//
|
|
||||||
// var a string = "Hello"
|
|
||||||
// var b string = "Hello"
|
|
||||||
//
|
|
||||||
// assert.Equal(a, b, "The two words should be the same.")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Assertions
|
|
||||||
//
|
|
||||||
// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
|
|
||||||
// All assertion functions take, as the first argument, the `*testing.T` object provided by the
|
|
||||||
// testing framework. This allows the assertion funcs to write the failings and other details to
|
|
||||||
// the correct place.
|
|
||||||
//
|
|
||||||
// Every assertion function also takes an optional string message as the final argument,
|
|
||||||
// allowing custom error messages to be appended to the message the assertion method outputs.
|
|
||||||
package assert
|
|
10
vendor/github.com/stretchr/testify/assert/errors.go
generated
vendored
10
vendor/github.com/stretchr/testify/assert/errors.go
generated
vendored
@ -1,10 +0,0 @@
|
|||||||
package assert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AnError is an error instance useful for testing. If the code does not care
|
|
||||||
// about error specifics, and only needs to return the error for example, this
|
|
||||||
// error should be used to make the test code more readable.
|
|
||||||
var AnError = errors.New("assert.AnError general error for testing")
|
|
16
vendor/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
16
vendor/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
package assert
|
|
||||||
|
|
||||||
// Assertions provides assertion methods around the
|
|
||||||
// TestingT interface.
|
|
||||||
type Assertions struct {
|
|
||||||
t TestingT
|
|
||||||
}
|
|
||||||
|
|
||||||
// New makes a new Assertions object for the specified TestingT.
|
|
||||||
func New(t TestingT) *Assertions {
|
|
||||||
return &Assertions{
|
|
||||||
t: t,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs
|
|
127
vendor/github.com/stretchr/testify/assert/http_assertions.go
generated
vendored
127
vendor/github.com/stretchr/testify/assert/http_assertions.go
generated
vendored
@ -1,127 +0,0 @@
|
|||||||
package assert
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// httpCode is a helper that returns HTTP code of the response. It returns -1 and
|
|
||||||
// an error if building a new request fails.
|
|
||||||
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
handler(w, req)
|
|
||||||
return w.Code, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPSuccess asserts that a specified handler returns a success status code.
|
|
||||||
//
|
|
||||||
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
|
|
||||||
code, err := httpCode(handler, method, url, values)
|
|
||||||
if err != nil {
|
|
||||||
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
|
|
||||||
if !isSuccessCode {
|
|
||||||
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code))
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSuccessCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPRedirect asserts that a specified handler returns a redirect status code.
|
|
||||||
//
|
|
||||||
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
|
|
||||||
code, err := httpCode(handler, method, url, values)
|
|
||||||
if err != nil {
|
|
||||||
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
|
|
||||||
if !isRedirectCode {
|
|
||||||
Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code))
|
|
||||||
}
|
|
||||||
|
|
||||||
return isRedirectCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPError asserts that a specified handler returns an error status code.
|
|
||||||
//
|
|
||||||
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values) bool {
|
|
||||||
code, err := httpCode(handler, method, url, values)
|
|
||||||
if err != nil {
|
|
||||||
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
isErrorCode := code >= http.StatusBadRequest
|
|
||||||
if !isErrorCode {
|
|
||||||
Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code))
|
|
||||||
}
|
|
||||||
|
|
||||||
return isErrorCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBody is a helper that returns HTTP body of the response. It returns
|
|
||||||
// empty string if building a new request fails.
|
|
||||||
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
handler(w, req)
|
|
||||||
return w.Body.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyContains asserts that a specified handler returns a
|
|
||||||
// body that contains a string.
|
|
||||||
//
|
|
||||||
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
|
|
||||||
body := HTTPBody(handler, method, url, values)
|
|
||||||
|
|
||||||
contains := strings.Contains(body, fmt.Sprint(str))
|
|
||||||
if !contains {
|
|
||||||
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
|
|
||||||
}
|
|
||||||
|
|
||||||
return contains
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
|
||||||
// body that does not contain a string.
|
|
||||||
//
|
|
||||||
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
|
||||||
//
|
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
|
||||||
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}) bool {
|
|
||||||
body := HTTPBody(handler, method, url, values)
|
|
||||||
|
|
||||||
contains := strings.Contains(body, fmt.Sprint(str))
|
|
||||||
if contains {
|
|
||||||
Fail(t, fmt.Sprintf("Expected response body for \"%s\" to NOT contain \"%s\" but found \"%s\"", url+"?"+values.Encode(), str, body))
|
|
||||||
}
|
|
||||||
|
|
||||||
return !contains
|
|
||||||
}
|
|
7
vendor/github.com/technoweenie/multipartstreamer/LICENSE
generated
vendored
7
vendor/github.com/technoweenie/multipartstreamer/LICENSE
generated
vendored
@ -1,7 +0,0 @@
|
|||||||
Copyright (c) 2013-* rick olson
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
47
vendor/github.com/technoweenie/multipartstreamer/README.md
generated
vendored
47
vendor/github.com/technoweenie/multipartstreamer/README.md
generated
vendored
@ -1,47 +0,0 @@
|
|||||||
# multipartstreamer
|
|
||||||
|
|
||||||
Package multipartstreamer helps you encode large files in MIME multipart format
|
|
||||||
without reading the entire content into memory. It uses io.MultiReader to
|
|
||||||
combine an inner multipart.Reader with a file handle.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/technoweenie/multipartstreamer.go"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
ms := multipartstreamer.New()
|
|
||||||
|
|
||||||
ms.WriteFields(map[string]string{
|
|
||||||
"key": "some-key",
|
|
||||||
"AWSAccessKeyId": "ABCDEF",
|
|
||||||
"acl": "some-acl",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Add any io.Reader to the multipart.Reader.
|
|
||||||
ms.WriteReader("file", "filename", some_ioReader, size)
|
|
||||||
|
|
||||||
// Shortcut for adding local file.
|
|
||||||
ms.WriteFile("file", "path/to/file")
|
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", "someurl", nil)
|
|
||||||
ms.SetupRequest(req)
|
|
||||||
|
|
||||||
res, _ := http.DefaultClient.Do(req)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
One limitation: You can only write a single file.
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
* Multiple files?
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
Heavily inspired by James
|
|
||||||
|
|
||||||
https://groups.google.com/forum/?fromgroups=#!topic/golang-nuts/Zjg5l4nKcQ0
|
|
101
vendor/github.com/technoweenie/multipartstreamer/multipartstreamer.go
generated
vendored
101
vendor/github.com/technoweenie/multipartstreamer/multipartstreamer.go
generated
vendored
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
Package multipartstreamer helps you encode large files in MIME multipart format
|
|
||||||
without reading the entire content into memory. It uses io.MultiReader to
|
|
||||||
combine an inner multipart.Reader with a file handle.
|
|
||||||
*/
|
|
||||||
package multipartstreamer
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"mime/multipart"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MultipartStreamer struct {
|
|
||||||
ContentType string
|
|
||||||
bodyBuffer *bytes.Buffer
|
|
||||||
bodyWriter *multipart.Writer
|
|
||||||
closeBuffer *bytes.Buffer
|
|
||||||
reader io.Reader
|
|
||||||
contentLength int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// New initializes a new MultipartStreamer.
|
|
||||||
func New() (m *MultipartStreamer) {
|
|
||||||
m = &MultipartStreamer{bodyBuffer: new(bytes.Buffer)}
|
|
||||||
|
|
||||||
m.bodyWriter = multipart.NewWriter(m.bodyBuffer)
|
|
||||||
boundary := m.bodyWriter.Boundary()
|
|
||||||
m.ContentType = "multipart/form-data; boundary=" + boundary
|
|
||||||
|
|
||||||
closeBoundary := fmt.Sprintf("\r\n--%s--\r\n", boundary)
|
|
||||||
m.closeBuffer = bytes.NewBufferString(closeBoundary)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteFields writes multiple form fields to the multipart.Writer.
|
|
||||||
func (m *MultipartStreamer) WriteFields(fields map[string]string) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
for key, value := range fields {
|
|
||||||
err = m.bodyWriter.WriteField(key, value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteReader adds an io.Reader to get the content of a file. The reader is
|
|
||||||
// not accessed until the multipart.Reader is copied to some output writer.
|
|
||||||
func (m *MultipartStreamer) WriteReader(key, filename string, size int64, reader io.Reader) (err error) {
|
|
||||||
m.reader = reader
|
|
||||||
m.contentLength = size
|
|
||||||
|
|
||||||
_, err = m.bodyWriter.CreateFormFile(key, filename)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteFile is a shortcut for adding a local file as an io.Reader.
|
|
||||||
func (m *MultipartStreamer) WriteFile(key, filename string) error {
|
|
||||||
fh, err := os.Open(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stat, err := fh.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return m.WriteReader(key, filepath.Base(filename), stat.Size(), fh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetupRequest sets up the http.Request body, and some crucial HTTP headers.
|
|
||||||
func (m *MultipartStreamer) SetupRequest(req *http.Request) {
|
|
||||||
req.Body = m.GetReader()
|
|
||||||
req.Header.Add("Content-Type", m.ContentType)
|
|
||||||
req.ContentLength = m.Len()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *MultipartStreamer) Boundary() string {
|
|
||||||
return m.bodyWriter.Boundary()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len calculates the byte size of the multipart content.
|
|
||||||
func (m *MultipartStreamer) Len() int64 {
|
|
||||||
return m.contentLength + int64(m.bodyBuffer.Len()) + int64(m.closeBuffer.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetReader gets an io.ReadCloser for passing to an http.Request.
|
|
||||||
func (m *MultipartStreamer) GetReader() io.ReadCloser {
|
|
||||||
reader := io.MultiReader(m.bodyBuffer, m.reader, m.closeBuffer)
|
|
||||||
return ioutil.NopCloser(reader)
|
|
||||||
}
|
|
392
vendor/github.com/urfave/cli/CHANGELOG.md
generated
vendored
392
vendor/github.com/urfave/cli/CHANGELOG.md
generated
vendored
@ -1,392 +0,0 @@
|
|||||||
# Change Log
|
|
||||||
|
|
||||||
**ATTN**: This project uses [semantic versioning](http://semver.org/).
|
|
||||||
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
## [1.19.1] - 2016-11-21
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
- Fixes regression introduced in 1.19.0 where using an `ActionFunc` as
|
|
||||||
the `Action` for a command would cause it to error rather than calling the
|
|
||||||
function. Should not have a affected declarative cases using `func(c
|
|
||||||
*cli.Context) err)`.
|
|
||||||
- Shell completion now handles the case where the user specifies
|
|
||||||
`--generate-bash-completion` immediately after a flag that takes an argument.
|
|
||||||
Previously it call the application with `--generate-bash-completion` as the
|
|
||||||
flag value.
|
|
||||||
|
|
||||||
## [1.19.0] - 2016-11-19
|
|
||||||
### Added
|
|
||||||
- `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`)
|
|
||||||
- A `Description` field was added to `App` for a more detailed description of
|
|
||||||
the application (similar to the existing `Description` field on `Command`)
|
|
||||||
- Flag type code generation via `go generate`
|
|
||||||
- Write to stderr and exit 1 if action returns non-nil error
|
|
||||||
- Added support for TOML to the `altsrc` loader
|
|
||||||
- `SkipArgReorder` was added to allow users to skip the argument reordering.
|
|
||||||
This is useful if you want to consider all "flags" after an argument as
|
|
||||||
arguments rather than flags (the default behavior of the stdlib `flag`
|
|
||||||
library). This is backported functionality from the [removal of the flag
|
|
||||||
reordering](https://github.com/urfave/cli/pull/398) in the unreleased version
|
|
||||||
2
|
|
||||||
- For formatted errors (those implementing `ErrorFormatter`), the errors will
|
|
||||||
be formatted during output. Compatible with `pkg/errors`.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Raise minimum tested/supported Go version to 1.2+
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Consider empty environment variables as set (previously environment variables
|
|
||||||
with the equivalent of `""` would be skipped rather than their value used).
|
|
||||||
- Return an error if the value in a given environment variable cannot be parsed
|
|
||||||
as the flag type. Previously these errors were silently swallowed.
|
|
||||||
- Print full error when an invalid flag is specified (which includes the invalid flag)
|
|
||||||
- `App.Writer` defaults to `stdout` when `nil`
|
|
||||||
- If no action is specified on a command or app, the help is now printed instead of `panic`ing
|
|
||||||
- `App.Metadata` is initialized automatically now (previously was `nil` unless initialized)
|
|
||||||
- Correctly show help message if `-h` is provided to a subcommand
|
|
||||||
- `context.(Global)IsSet` now respects environment variables. Previously it
|
|
||||||
would return `false` if a flag was specified in the environment rather than
|
|
||||||
as an argument
|
|
||||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user
|
|
||||||
- `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This
|
|
||||||
fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well
|
|
||||||
as `altsrc` where Go would complain that the types didn't match
|
|
||||||
|
|
||||||
## [1.18.1] - 2016-08-28
|
|
||||||
### Fixed
|
|
||||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported)
|
|
||||||
|
|
||||||
## [1.18.0] - 2016-06-27
|
|
||||||
### Added
|
|
||||||
- `./runtests` test runner with coverage tracking by default
|
|
||||||
- testing on OS X
|
|
||||||
- testing on Windows
|
|
||||||
- `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Use spaces for alignment in help/usage output instead of tabs, making the
|
|
||||||
output alignment consistent regardless of tab width
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Printing of command aliases in help text
|
|
||||||
- Printing of visible flags for both struct and struct pointer flags
|
|
||||||
- Display the `help` subcommand when using `CommandCategories`
|
|
||||||
- No longer swallows `panic`s that occur within the `Action`s themselves when
|
|
||||||
detecting the signature of the `Action` field
|
|
||||||
|
|
||||||
## [1.17.1] - 2016-08-28
|
|
||||||
### Fixed
|
|
||||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user
|
|
||||||
|
|
||||||
## [1.17.0] - 2016-05-09
|
|
||||||
### Added
|
|
||||||
- Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc`
|
|
||||||
- `context.GlobalBoolT` was added as an analogue to `context.GlobalBool`
|
|
||||||
- Support for hiding commands by setting `Hidden: true` -- this will hide the
|
|
||||||
commands in help output
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer
|
|
||||||
quoted in help text output.
|
|
||||||
- All flag types now include `(default: {value})` strings following usage when a
|
|
||||||
default value can be (reasonably) detected.
|
|
||||||
- `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent
|
|
||||||
with non-slice flag types
|
|
||||||
- Apps now exit with a code of 3 if an unknown subcommand is specified
|
|
||||||
(previously they printed "No help topic for...", but still exited 0. This
|
|
||||||
makes it easier to script around apps built using `cli` since they can trust
|
|
||||||
that a 0 exit code indicated a successful execution.
|
|
||||||
- cleanups based on [Go Report Card
|
|
||||||
feedback](https://goreportcard.com/report/github.com/urfave/cli)
|
|
||||||
|
|
||||||
## [1.16.1] - 2016-08-28
|
|
||||||
### Fixed
|
|
||||||
- Removed deprecation warnings to STDERR to avoid them leaking to the end-user
|
|
||||||
|
|
||||||
## [1.16.0] - 2016-05-02
|
|
||||||
### Added
|
|
||||||
- `Hidden` field on all flag struct types to omit from generated help text
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from
|
|
||||||
generated help text via the `Hidden` field
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- handling of error values in `HandleAction` and `HandleExitCoder`
|
|
||||||
|
|
||||||
## [1.15.0] - 2016-04-30
|
|
||||||
### Added
|
|
||||||
- This file!
|
|
||||||
- Support for placeholders in flag usage strings
|
|
||||||
- `App.Metadata` map for arbitrary data/state management
|
|
||||||
- `Set` and `GlobalSet` methods on `*cli.Context` for altering values after
|
|
||||||
parsing.
|
|
||||||
- Support for nested lookup of dot-delimited keys in structures loaded from
|
|
||||||
YAML.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- The `App.Action` and `Command.Action` now prefer a return signature of
|
|
||||||
`func(*cli.Context) error`, as defined by `cli.ActionFunc`. If a non-nil
|
|
||||||
`error` is returned, there may be two outcomes:
|
|
||||||
- If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called
|
|
||||||
automatically
|
|
||||||
- Else the error is bubbled up and returned from `App.Run`
|
|
||||||
- Specifying an `Action` with the legacy return signature of
|
|
||||||
`func(*cli.Context)` will produce a deprecation message to stderr
|
|
||||||
- Specifying an `Action` that is not a `func` type will produce a non-zero exit
|
|
||||||
from `App.Run`
|
|
||||||
- Specifying an `Action` func that has an invalid (input) signature will
|
|
||||||
produce a non-zero exit from `App.Run`
|
|
||||||
|
|
||||||
### Deprecated
|
|
||||||
- <a name="deprecated-cli-app-runandexitonerror"></a>
|
|
||||||
`cli.App.RunAndExitOnError`, which should now be done by returning an error
|
|
||||||
that fulfills `cli.ExitCoder` to `cli.App.Run`.
|
|
||||||
- <a name="deprecated-cli-app-action-signature"></a> the legacy signature for
|
|
||||||
`cli.App.Action` of `func(*cli.Context)`, which should now have a return
|
|
||||||
signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Added missing `*cli.Context.GlobalFloat64` method
|
|
||||||
|
|
||||||
## [1.14.0] - 2016-04-03 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Codebeat badge
|
|
||||||
- Support for categorization via `CategorizedHelp` and `Categories` on app.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Ensure version is not shown in help text when `HideVersion` set.
|
|
||||||
|
|
||||||
## [1.13.0] - 2016-03-06 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- YAML file input support.
|
|
||||||
- `NArg` method on context.
|
|
||||||
|
|
||||||
## [1.12.0] - 2016-02-17 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Custom usage error handling.
|
|
||||||
- Custom text support in `USAGE` section of help output.
|
|
||||||
- Improved help messages for empty strings.
|
|
||||||
- AppVeyor CI configuration.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Removed `panic` from default help printer func.
|
|
||||||
- De-duping and optimizations.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Correctly handle `Before`/`After` at command level when no subcommands.
|
|
||||||
- Case of literal `-` argument causing flag reordering.
|
|
||||||
- Environment variable hints on Windows.
|
|
||||||
- Docs updates.
|
|
||||||
|
|
||||||
## [1.11.1] - 2015-12-21 (backfilled 2016-04-25)
|
|
||||||
### Changed
|
|
||||||
- Use `path.Base` in `Name` and `HelpName`
|
|
||||||
- Export `GetName` on flag types.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Flag parsing when skipping is enabled.
|
|
||||||
- Test output cleanup.
|
|
||||||
- Move completion check to account for empty input case.
|
|
||||||
|
|
||||||
## [1.11.0] - 2015-11-15 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Destination scan support for flags.
|
|
||||||
- Testing against `tip` in Travis CI config.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Go version in Travis CI config.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Removed redundant tests.
|
|
||||||
- Use correct example naming in tests.
|
|
||||||
|
|
||||||
## [1.10.2] - 2015-10-29 (backfilled 2016-04-25)
|
|
||||||
### Fixed
|
|
||||||
- Remove unused var in bash completion.
|
|
||||||
|
|
||||||
## [1.10.1] - 2015-10-21 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Coverage and reference logos in README.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Use specified values in help and version parsing.
|
|
||||||
- Only display app version and help message once.
|
|
||||||
|
|
||||||
## [1.10.0] - 2015-10-06 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- More tests for existing functionality.
|
|
||||||
- `ArgsUsage` at app and command level for help text flexibility.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Honor `HideHelp` and `HideVersion` in `App.Run`.
|
|
||||||
- Remove juvenile word from README.
|
|
||||||
|
|
||||||
## [1.9.0] - 2015-09-08 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- `FullName` on command with accompanying help output update.
|
|
||||||
- Set default `$PROG` in bash completion.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Docs formatting.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Removed self-referential imports in tests.
|
|
||||||
|
|
||||||
## [1.8.0] - 2015-06-30 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Support for `Copyright` at app level.
|
|
||||||
- `Parent` func at context level to walk up context lineage.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Global flag processing at top level.
|
|
||||||
|
|
||||||
## [1.7.1] - 2015-06-11 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Aggregate errors from `Before`/`After` funcs.
|
|
||||||
- Doc comments on flag structs.
|
|
||||||
- Include non-global flags when checking version and help.
|
|
||||||
- Travis CI config updates.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Ensure slice type flags have non-nil values.
|
|
||||||
- Collect global flags from the full command hierarchy.
|
|
||||||
- Docs prose.
|
|
||||||
|
|
||||||
## [1.7.0] - 2015-05-03 (backfilled 2016-04-25)
|
|
||||||
### Changed
|
|
||||||
- `HelpPrinter` signature includes output writer.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Specify go 1.1+ in docs.
|
|
||||||
- Set `Writer` when running command as app.
|
|
||||||
|
|
||||||
## [1.6.0] - 2015-03-23 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Multiple author support.
|
|
||||||
- `NumFlags` at context level.
|
|
||||||
- `Aliases` at command level.
|
|
||||||
|
|
||||||
### Deprecated
|
|
||||||
- `ShortName` at command level.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Subcommand help output.
|
|
||||||
- Backward compatible support for deprecated `Author` and `Email` fields.
|
|
||||||
- Docs regarding `Names`/`Aliases`.
|
|
||||||
|
|
||||||
## [1.5.0] - 2015-02-20 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- `After` hook func support at app and command level.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Use parsed context when running command as subcommand.
|
|
||||||
- Docs prose.
|
|
||||||
|
|
||||||
## [1.4.1] - 2015-01-09 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Support for hiding `-h / --help` flags, but not `help` subcommand.
|
|
||||||
- Stop flag parsing after `--`.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Help text for generic flags to specify single value.
|
|
||||||
- Use double quotes in output for defaults.
|
|
||||||
- Use `ParseInt` instead of `ParseUint` for int environment var values.
|
|
||||||
- Use `0` as base when parsing int environment var values.
|
|
||||||
|
|
||||||
## [1.4.0] - 2014-12-12 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Support for environment variable lookup "cascade".
|
|
||||||
- Support for `Stdout` on app for output redirection.
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Print command help instead of app help in `ShowCommandHelp`.
|
|
||||||
|
|
||||||
## [1.3.1] - 2014-11-13 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- Docs and example code updates.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Default `-v / --version` flag made optional.
|
|
||||||
|
|
||||||
## [1.3.0] - 2014-08-10 (backfilled 2016-04-25)
|
|
||||||
### Added
|
|
||||||
- `FlagNames` at context level.
|
|
||||||
- Exposed `VersionPrinter` var for more control over version output.
|
|
||||||
- Zsh completion hook.
|
|
||||||
- `AUTHOR` section in default app help template.
|
|
||||||
- Contribution guidelines.
|
|
||||||
- `DurationFlag` type.
|
|
||||||
|
|
||||||
## [1.2.0] - 2014-08-02
|
|
||||||
### Added
|
|
||||||
- Support for environment variable defaults on flags plus tests.
|
|
||||||
|
|
||||||
## [1.1.0] - 2014-07-15
|
|
||||||
### Added
|
|
||||||
- Bash completion.
|
|
||||||
- Optional hiding of built-in help command.
|
|
||||||
- Optional skipping of flag parsing at command level.
|
|
||||||
- `Author`, `Email`, and `Compiled` metadata on app.
|
|
||||||
- `Before` hook func support at app and command level.
|
|
||||||
- `CommandNotFound` func support at app level.
|
|
||||||
- Command reference available on context.
|
|
||||||
- `GenericFlag` type.
|
|
||||||
- `Float64Flag` type.
|
|
||||||
- `BoolTFlag` type.
|
|
||||||
- `IsSet` flag helper on context.
|
|
||||||
- More flag lookup funcs at context level.
|
|
||||||
- More tests & docs.
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Help template updates to account for presence/absence of flags.
|
|
||||||
- Separated subcommand help template.
|
|
||||||
- Exposed `HelpPrinter` var for more control over help output.
|
|
||||||
|
|
||||||
## [1.0.0] - 2013-11-01
|
|
||||||
### Added
|
|
||||||
- `help` flag in default app flag set and each command flag set.
|
|
||||||
- Custom handling of argument parsing errors.
|
|
||||||
- Command lookup by name at app level.
|
|
||||||
- `StringSliceFlag` type and supporting `StringSlice` type.
|
|
||||||
- `IntSliceFlag` type and supporting `IntSlice` type.
|
|
||||||
- Slice type flag lookups by name at context level.
|
|
||||||
- Export of app and command help functions.
|
|
||||||
- More tests & docs.
|
|
||||||
|
|
||||||
## 0.1.0 - 2013-07-22
|
|
||||||
### Added
|
|
||||||
- Initial implementation.
|
|
||||||
|
|
||||||
[Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD
|
|
||||||
[1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0
|
|
||||||
[1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0
|
|
||||||
[1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0
|
|
||||||
[1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0
|
|
||||||
[1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0
|
|
||||||
[1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0
|
|
||||||
[1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0
|
|
||||||
[1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1
|
|
||||||
[1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0
|
|
||||||
[1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2
|
|
||||||
[1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1
|
|
||||||
[1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0
|
|
||||||
[1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0
|
|
||||||
[1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0
|
|
||||||
[1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1
|
|
||||||
[1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0
|
|
||||||
[1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0
|
|
||||||
[1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0
|
|
||||||
[1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1
|
|
||||||
[1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0
|
|
||||||
[1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1
|
|
||||||
[1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0
|
|
||||||
[1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0
|
|
||||||
[1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0
|
|
||||||
[1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0
|
|
21
vendor/github.com/urfave/cli/LICENSE
generated
vendored
21
vendor/github.com/urfave/cli/LICENSE
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2016 Jeremy Saenz & Contributors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
1381
vendor/github.com/urfave/cli/README.md
generated
vendored
1381
vendor/github.com/urfave/cli/README.md
generated
vendored
File diff suppressed because it is too large
Load Diff
497
vendor/github.com/urfave/cli/app.go
generated
vendored
497
vendor/github.com/urfave/cli/app.go
generated
vendored
@ -1,497 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"
|
|
||||||
appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
|
|
||||||
runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)
|
|
||||||
|
|
||||||
contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
|
|
||||||
|
|
||||||
errInvalidActionType = NewExitError("ERROR invalid Action type. "+
|
|
||||||
fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
|
|
||||||
fmt.Sprintf("See %s", appActionDeprecationURL), 2)
|
|
||||||
)
|
|
||||||
|
|
||||||
// App is the main structure of a cli application. It is recommended that
|
|
||||||
// an app be created with the cli.NewApp() function
|
|
||||||
type App struct {
|
|
||||||
// The name of the program. Defaults to path.Base(os.Args[0])
|
|
||||||
Name string
|
|
||||||
// Full name of command for help, defaults to Name
|
|
||||||
HelpName string
|
|
||||||
// Description of the program.
|
|
||||||
Usage string
|
|
||||||
// Text to override the USAGE section of help
|
|
||||||
UsageText string
|
|
||||||
// Description of the program argument format.
|
|
||||||
ArgsUsage string
|
|
||||||
// Version of the program
|
|
||||||
Version string
|
|
||||||
// Description of the program
|
|
||||||
Description string
|
|
||||||
// List of commands to execute
|
|
||||||
Commands []Command
|
|
||||||
// List of flags to parse
|
|
||||||
Flags []Flag
|
|
||||||
// Boolean to enable bash completion commands
|
|
||||||
EnableBashCompletion bool
|
|
||||||
// Boolean to hide built-in help command
|
|
||||||
HideHelp bool
|
|
||||||
// Boolean to hide built-in version flag and the VERSION section of help
|
|
||||||
HideVersion bool
|
|
||||||
// Populate on app startup, only gettable through method Categories()
|
|
||||||
categories CommandCategories
|
|
||||||
// An action to execute when the bash-completion flag is set
|
|
||||||
BashComplete BashCompleteFunc
|
|
||||||
// An action to execute before any subcommands are run, but after the context is ready
|
|
||||||
// If a non-nil error is returned, no subcommands are run
|
|
||||||
Before BeforeFunc
|
|
||||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
|
||||||
// It is run even if Action() panics
|
|
||||||
After AfterFunc
|
|
||||||
|
|
||||||
// The action to execute when no subcommands are specified
|
|
||||||
// Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}`
|
|
||||||
// *Note*: support for the deprecated `Action` signature will be removed in a future version
|
|
||||||
Action interface{}
|
|
||||||
|
|
||||||
// Execute this function if the proper command cannot be found
|
|
||||||
CommandNotFound CommandNotFoundFunc
|
|
||||||
// Execute this function if an usage error occurs
|
|
||||||
OnUsageError OnUsageErrorFunc
|
|
||||||
// Compilation date
|
|
||||||
Compiled time.Time
|
|
||||||
// List of all authors who contributed
|
|
||||||
Authors []Author
|
|
||||||
// Copyright of the binary if any
|
|
||||||
Copyright string
|
|
||||||
// Name of Author (Note: Use App.Authors, this is deprecated)
|
|
||||||
Author string
|
|
||||||
// Email of Author (Note: Use App.Authors, this is deprecated)
|
|
||||||
Email string
|
|
||||||
// Writer writer to write output to
|
|
||||||
Writer io.Writer
|
|
||||||
// ErrWriter writes error output
|
|
||||||
ErrWriter io.Writer
|
|
||||||
// Other custom info
|
|
||||||
Metadata map[string]interface{}
|
|
||||||
// Carries a function which returns app specific info.
|
|
||||||
ExtraInfo func() map[string]string
|
|
||||||
// CustomAppHelpTemplate the text template for app help topic.
|
|
||||||
// cli.go uses text/template to render templates. You can
|
|
||||||
// render custom help text by setting this variable.
|
|
||||||
CustomAppHelpTemplate string
|
|
||||||
|
|
||||||
didSetup bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tries to find out when this binary was compiled.
|
|
||||||
// Returns the current time if it fails to find it.
|
|
||||||
func compileTime() time.Time {
|
|
||||||
info, err := os.Stat(os.Args[0])
|
|
||||||
if err != nil {
|
|
||||||
return time.Now()
|
|
||||||
}
|
|
||||||
return info.ModTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewApp creates a new cli Application with some reasonable defaults for Name,
|
|
||||||
// Usage, Version and Action.
|
|
||||||
func NewApp() *App {
|
|
||||||
return &App{
|
|
||||||
Name: filepath.Base(os.Args[0]),
|
|
||||||
HelpName: filepath.Base(os.Args[0]),
|
|
||||||
Usage: "A new cli application",
|
|
||||||
UsageText: "",
|
|
||||||
Version: "0.0.0",
|
|
||||||
BashComplete: DefaultAppComplete,
|
|
||||||
Action: helpCommand.Action,
|
|
||||||
Compiled: compileTime(),
|
|
||||||
Writer: os.Stdout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup runs initialization code to ensure all data structures are ready for
|
|
||||||
// `Run` or inspection prior to `Run`. It is internally called by `Run`, but
|
|
||||||
// will return early if setup has already happened.
|
|
||||||
func (a *App) Setup() {
|
|
||||||
if a.didSetup {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
a.didSetup = true
|
|
||||||
|
|
||||||
if a.Author != "" || a.Email != "" {
|
|
||||||
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
|
|
||||||
}
|
|
||||||
|
|
||||||
newCmds := []Command{}
|
|
||||||
for _, c := range a.Commands {
|
|
||||||
if c.HelpName == "" {
|
|
||||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
|
||||||
}
|
|
||||||
newCmds = append(newCmds, c)
|
|
||||||
}
|
|
||||||
a.Commands = newCmds
|
|
||||||
|
|
||||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
|
||||||
a.Commands = append(a.Commands, helpCommand)
|
|
||||||
if (HelpFlag != BoolFlag{}) {
|
|
||||||
a.appendFlag(HelpFlag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !a.HideVersion {
|
|
||||||
a.appendFlag(VersionFlag)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.categories = CommandCategories{}
|
|
||||||
for _, command := range a.Commands {
|
|
||||||
a.categories = a.categories.AddCommand(command.Category, command)
|
|
||||||
}
|
|
||||||
sort.Sort(a.categories)
|
|
||||||
|
|
||||||
if a.Metadata == nil {
|
|
||||||
a.Metadata = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Writer == nil {
|
|
||||||
a.Writer = os.Stdout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run is the entry point to the cli app. Parses the arguments slice and routes
|
|
||||||
// to the proper flag/args combination
|
|
||||||
func (a *App) Run(arguments []string) (err error) {
|
|
||||||
a.Setup()
|
|
||||||
|
|
||||||
// handle the completion flag separately from the flagset since
|
|
||||||
// completion could be attempted after a flag, but before its value was put
|
|
||||||
// on the command line. this causes the flagset to interpret the completion
|
|
||||||
// flag name as the value of the flag before it which is undesirable
|
|
||||||
// note that we can only do this because the shell autocomplete function
|
|
||||||
// always appends the completion flag at the end of the command
|
|
||||||
shellComplete, arguments := checkShellCompleteFlag(a, arguments)
|
|
||||||
|
|
||||||
// parse flags
|
|
||||||
set, err := flagSet(a.Name, a.Flags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
set.SetOutput(ioutil.Discard)
|
|
||||||
err = set.Parse(arguments[1:])
|
|
||||||
nerr := normalizeFlags(a.Flags, set)
|
|
||||||
context := NewContext(a, set, nil)
|
|
||||||
if nerr != nil {
|
|
||||||
fmt.Fprintln(a.Writer, nerr)
|
|
||||||
ShowAppHelp(context)
|
|
||||||
return nerr
|
|
||||||
}
|
|
||||||
context.shellComplete = shellComplete
|
|
||||||
|
|
||||||
if checkCompletions(context) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if a.OnUsageError != nil {
|
|
||||||
err := a.OnUsageError(context, err, false)
|
|
||||||
HandleExitCoder(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
|
|
||||||
ShowAppHelp(context)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !a.HideHelp && checkHelp(context) {
|
|
||||||
ShowAppHelp(context)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !a.HideVersion && checkVersion(context) {
|
|
||||||
ShowVersion(context)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.After != nil {
|
|
||||||
defer func() {
|
|
||||||
if afterErr := a.After(context); afterErr != nil {
|
|
||||||
if err != nil {
|
|
||||||
err = NewMultiError(err, afterErr)
|
|
||||||
} else {
|
|
||||||
err = afterErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Before != nil {
|
|
||||||
beforeErr := a.Before(context)
|
|
||||||
if beforeErr != nil {
|
|
||||||
ShowAppHelp(context)
|
|
||||||
HandleExitCoder(beforeErr)
|
|
||||||
err = beforeErr
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
args := context.Args()
|
|
||||||
if args.Present() {
|
|
||||||
name := args.First()
|
|
||||||
c := a.Command(name)
|
|
||||||
if c != nil {
|
|
||||||
return c.Run(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Action == nil {
|
|
||||||
a.Action = helpCommand.Action
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run default Action
|
|
||||||
err = HandleAction(a.Action, context)
|
|
||||||
|
|
||||||
HandleExitCoder(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunAndExitOnError calls .Run() and exits non-zero if an error was returned
|
|
||||||
//
|
|
||||||
// Deprecated: instead you should return an error that fulfills cli.ExitCoder
|
|
||||||
// to cli.App.Run. This will cause the application to exit with the given eror
|
|
||||||
// code in the cli.ExitCoder
|
|
||||||
func (a *App) RunAndExitOnError() {
|
|
||||||
if err := a.Run(os.Args); err != nil {
|
|
||||||
fmt.Fprintln(a.errWriter(), err)
|
|
||||||
OsExiter(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
|
|
||||||
// generate command-specific flags
|
|
||||||
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|
||||||
// append help to commands
|
|
||||||
if len(a.Commands) > 0 {
|
|
||||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
|
||||||
a.Commands = append(a.Commands, helpCommand)
|
|
||||||
if (HelpFlag != BoolFlag{}) {
|
|
||||||
a.appendFlag(HelpFlag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newCmds := []Command{}
|
|
||||||
for _, c := range a.Commands {
|
|
||||||
if c.HelpName == "" {
|
|
||||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
|
||||||
}
|
|
||||||
newCmds = append(newCmds, c)
|
|
||||||
}
|
|
||||||
a.Commands = newCmds
|
|
||||||
|
|
||||||
// parse flags
|
|
||||||
set, err := flagSet(a.Name, a.Flags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
set.SetOutput(ioutil.Discard)
|
|
||||||
err = set.Parse(ctx.Args().Tail())
|
|
||||||
nerr := normalizeFlags(a.Flags, set)
|
|
||||||
context := NewContext(a, set, ctx)
|
|
||||||
|
|
||||||
if nerr != nil {
|
|
||||||
fmt.Fprintln(a.Writer, nerr)
|
|
||||||
fmt.Fprintln(a.Writer)
|
|
||||||
if len(a.Commands) > 0 {
|
|
||||||
ShowSubcommandHelp(context)
|
|
||||||
} else {
|
|
||||||
ShowCommandHelp(ctx, context.Args().First())
|
|
||||||
}
|
|
||||||
return nerr
|
|
||||||
}
|
|
||||||
|
|
||||||
if checkCompletions(context) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if a.OnUsageError != nil {
|
|
||||||
err = a.OnUsageError(context, err, true)
|
|
||||||
HandleExitCoder(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
|
|
||||||
ShowSubcommandHelp(context)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(a.Commands) > 0 {
|
|
||||||
if checkSubcommandHelp(context) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if checkCommandHelp(ctx, context.Args().First()) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.After != nil {
|
|
||||||
defer func() {
|
|
||||||
afterErr := a.After(context)
|
|
||||||
if afterErr != nil {
|
|
||||||
HandleExitCoder(err)
|
|
||||||
if err != nil {
|
|
||||||
err = NewMultiError(err, afterErr)
|
|
||||||
} else {
|
|
||||||
err = afterErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Before != nil {
|
|
||||||
beforeErr := a.Before(context)
|
|
||||||
if beforeErr != nil {
|
|
||||||
HandleExitCoder(beforeErr)
|
|
||||||
err = beforeErr
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
args := context.Args()
|
|
||||||
if args.Present() {
|
|
||||||
name := args.First()
|
|
||||||
c := a.Command(name)
|
|
||||||
if c != nil {
|
|
||||||
return c.Run(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run default Action
|
|
||||||
err = HandleAction(a.Action, context)
|
|
||||||
|
|
||||||
HandleExitCoder(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the named command on App. Returns nil if the command does not exist
|
|
||||||
func (a *App) Command(name string) *Command {
|
|
||||||
for _, c := range a.Commands {
|
|
||||||
if c.HasName(name) {
|
|
||||||
return &c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Categories returns a slice containing all the categories with the commands they contain
|
|
||||||
func (a *App) Categories() CommandCategories {
|
|
||||||
return a.categories
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleCategories returns a slice of categories and commands that are
|
|
||||||
// Hidden=false
|
|
||||||
func (a *App) VisibleCategories() []*CommandCategory {
|
|
||||||
ret := []*CommandCategory{}
|
|
||||||
for _, category := range a.categories {
|
|
||||||
if visible := func() *CommandCategory {
|
|
||||||
for _, command := range category.Commands {
|
|
||||||
if !command.Hidden {
|
|
||||||
return category
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}(); visible != nil {
|
|
||||||
ret = append(ret, visible)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
|
||||||
func (a *App) VisibleCommands() []Command {
|
|
||||||
ret := []Command{}
|
|
||||||
for _, command := range a.Commands {
|
|
||||||
if !command.Hidden {
|
|
||||||
ret = append(ret, command)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
|
||||||
func (a *App) VisibleFlags() []Flag {
|
|
||||||
return visibleFlags(a.Flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) hasFlag(flag Flag) bool {
|
|
||||||
for _, f := range a.Flags {
|
|
||||||
if flag == f {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) errWriter() io.Writer {
|
|
||||||
|
|
||||||
// When the app ErrWriter is nil use the package level one.
|
|
||||||
if a.ErrWriter == nil {
|
|
||||||
return ErrWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.ErrWriter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *App) appendFlag(flag Flag) {
|
|
||||||
if !a.hasFlag(flag) {
|
|
||||||
a.Flags = append(a.Flags, flag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Author represents someone who has contributed to a cli project.
|
|
||||||
type Author struct {
|
|
||||||
Name string // The Authors name
|
|
||||||
Email string // The Authors email
|
|
||||||
}
|
|
||||||
|
|
||||||
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
|
||||||
func (a Author) String() string {
|
|
||||||
e := ""
|
|
||||||
if a.Email != "" {
|
|
||||||
e = " <" + a.Email + ">"
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%v%v", a.Name, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleAction attempts to figure out which Action signature was used. If
|
|
||||||
// it's an ActionFunc or a func with the legacy signature for Action, the func
|
|
||||||
// is run!
|
|
||||||
func HandleAction(action interface{}, context *Context) (err error) {
|
|
||||||
if a, ok := action.(ActionFunc); ok {
|
|
||||||
return a(context)
|
|
||||||
} else if a, ok := action.(func(*Context) error); ok {
|
|
||||||
return a(context)
|
|
||||||
} else if a, ok := action.(func(*Context)); ok { // deprecated function signature
|
|
||||||
a(context)
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return errInvalidActionType
|
|
||||||
}
|
|
||||||
}
|
|
24
vendor/github.com/urfave/cli/appveyor.yml
generated
vendored
24
vendor/github.com/urfave/cli/appveyor.yml
generated
vendored
@ -1,24 +0,0 @@
|
|||||||
version: "{build}"
|
|
||||||
|
|
||||||
os: Windows Server 2012 R2
|
|
||||||
|
|
||||||
clone_folder: c:\gopath\src\github.com\urfave\cli
|
|
||||||
|
|
||||||
environment:
|
|
||||||
GOPATH: C:\gopath
|
|
||||||
GOVERSION: 1.6
|
|
||||||
PYTHON: C:\Python27-x64
|
|
||||||
PYTHON_VERSION: 2.7.x
|
|
||||||
PYTHON_ARCH: 64
|
|
||||||
|
|
||||||
install:
|
|
||||||
- set PATH=%GOPATH%\bin;C:\go\bin;%PATH%
|
|
||||||
- go version
|
|
||||||
- go env
|
|
||||||
- go get github.com/urfave/gfmrun/...
|
|
||||||
- go get -v -t ./...
|
|
||||||
|
|
||||||
build_script:
|
|
||||||
- python runtests vet
|
|
||||||
- python runtests test
|
|
||||||
- python runtests gfmrun
|
|
44
vendor/github.com/urfave/cli/category.go
generated
vendored
44
vendor/github.com/urfave/cli/category.go
generated
vendored
@ -1,44 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
// CommandCategories is a slice of *CommandCategory.
|
|
||||||
type CommandCategories []*CommandCategory
|
|
||||||
|
|
||||||
// CommandCategory is a category containing commands.
|
|
||||||
type CommandCategory struct {
|
|
||||||
Name string
|
|
||||||
Commands Commands
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommandCategories) Less(i, j int) bool {
|
|
||||||
return c[i].Name < c[j].Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommandCategories) Len() int {
|
|
||||||
return len(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommandCategories) Swap(i, j int) {
|
|
||||||
c[i], c[j] = c[j], c[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddCommand adds a command to a category.
|
|
||||||
func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
|
|
||||||
for _, commandCategory := range c {
|
|
||||||
if commandCategory.Name == category {
|
|
||||||
commandCategory.Commands = append(commandCategory.Commands, command)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
|
||||||
func (c *CommandCategory) VisibleCommands() []Command {
|
|
||||||
ret := []Command{}
|
|
||||||
for _, command := range c.Commands {
|
|
||||||
if !command.Hidden {
|
|
||||||
ret = append(ret, command)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
21
vendor/github.com/urfave/cli/cli.go
generated
vendored
21
vendor/github.com/urfave/cli/cli.go
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
// Package cli provides a minimal framework for creating and organizing command line
|
|
||||||
// Go applications. cli is designed to be easy to understand and write, the most simple
|
|
||||||
// cli application can be written as follows:
|
|
||||||
// func main() {
|
|
||||||
// cli.NewApp().Run(os.Args)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Of course this application does not do much, so let's make this an actual application:
|
|
||||||
// func main() {
|
|
||||||
// app := cli.NewApp()
|
|
||||||
// app.Name = "greet"
|
|
||||||
// app.Usage = "say a greeting"
|
|
||||||
// app.Action = func(c *cli.Context) error {
|
|
||||||
// println("Greetings")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// app.Run(os.Args)
|
|
||||||
// }
|
|
||||||
package cli
|
|
||||||
|
|
||||||
//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go
|
|
304
vendor/github.com/urfave/cli/command.go
generated
vendored
304
vendor/github.com/urfave/cli/command.go
generated
vendored
@ -1,304 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Command is a subcommand for a cli.App.
|
|
||||||
type Command struct {
|
|
||||||
// The name of the command
|
|
||||||
Name string
|
|
||||||
// short name of the command. Typically one character (deprecated, use `Aliases`)
|
|
||||||
ShortName string
|
|
||||||
// A list of aliases for the command
|
|
||||||
Aliases []string
|
|
||||||
// A short description of the usage of this command
|
|
||||||
Usage string
|
|
||||||
// Custom text to show on USAGE section of help
|
|
||||||
UsageText string
|
|
||||||
// A longer explanation of how the command works
|
|
||||||
Description string
|
|
||||||
// A short description of the arguments of this command
|
|
||||||
ArgsUsage string
|
|
||||||
// The category the command is part of
|
|
||||||
Category string
|
|
||||||
// The function to call when checking for bash command completions
|
|
||||||
BashComplete BashCompleteFunc
|
|
||||||
// An action to execute before any sub-subcommands are run, but after the context is ready
|
|
||||||
// If a non-nil error is returned, no sub-subcommands are run
|
|
||||||
Before BeforeFunc
|
|
||||||
// An action to execute after any subcommands are run, but after the subcommand has finished
|
|
||||||
// It is run even if Action() panics
|
|
||||||
After AfterFunc
|
|
||||||
// The function to call when this command is invoked
|
|
||||||
Action interface{}
|
|
||||||
// TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
|
|
||||||
// of deprecation period has passed, maybe?
|
|
||||||
|
|
||||||
// Execute this function if a usage error occurs.
|
|
||||||
OnUsageError OnUsageErrorFunc
|
|
||||||
// List of child commands
|
|
||||||
Subcommands Commands
|
|
||||||
// List of flags to parse
|
|
||||||
Flags []Flag
|
|
||||||
// Treat all flags as normal arguments if true
|
|
||||||
SkipFlagParsing bool
|
|
||||||
// Skip argument reordering which attempts to move flags before arguments,
|
|
||||||
// but only works if all flags appear after all arguments. This behavior was
|
|
||||||
// removed n version 2 since it only works under specific conditions so we
|
|
||||||
// backport here by exposing it as an option for compatibility.
|
|
||||||
SkipArgReorder bool
|
|
||||||
// Boolean to hide built-in help command
|
|
||||||
HideHelp bool
|
|
||||||
// Boolean to hide this command from help or completion
|
|
||||||
Hidden bool
|
|
||||||
|
|
||||||
// Full name of command for help, defaults to full command name, including parent commands.
|
|
||||||
HelpName string
|
|
||||||
commandNamePath []string
|
|
||||||
|
|
||||||
// CustomHelpTemplate the text template for the command help topic.
|
|
||||||
// cli.go uses text/template to render templates. You can
|
|
||||||
// render custom help text by setting this variable.
|
|
||||||
CustomHelpTemplate string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CommandsByName []Command
|
|
||||||
|
|
||||||
func (c CommandsByName) Len() int {
|
|
||||||
return len(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommandsByName) Less(i, j int) bool {
|
|
||||||
return c[i].Name < c[j].Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c CommandsByName) Swap(i, j int) {
|
|
||||||
c[i], c[j] = c[j], c[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// FullName returns the full name of the command.
|
|
||||||
// For subcommands this ensures that parent commands are part of the command path
|
|
||||||
func (c Command) FullName() string {
|
|
||||||
if c.commandNamePath == nil {
|
|
||||||
return c.Name
|
|
||||||
}
|
|
||||||
return strings.Join(c.commandNamePath, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commands is a slice of Command
|
|
||||||
type Commands []Command
|
|
||||||
|
|
||||||
// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
|
||||||
func (c Command) Run(ctx *Context) (err error) {
|
|
||||||
if len(c.Subcommands) > 0 {
|
|
||||||
return c.startApp(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
|
|
||||||
// append help to flags
|
|
||||||
c.Flags = append(
|
|
||||||
c.Flags,
|
|
||||||
HelpFlag,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
set, err := flagSet(c.Name, c.Flags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
set.SetOutput(ioutil.Discard)
|
|
||||||
|
|
||||||
if c.SkipFlagParsing {
|
|
||||||
err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...))
|
|
||||||
} else if !c.SkipArgReorder {
|
|
||||||
firstFlagIndex := -1
|
|
||||||
terminatorIndex := -1
|
|
||||||
for index, arg := range ctx.Args() {
|
|
||||||
if arg == "--" {
|
|
||||||
terminatorIndex = index
|
|
||||||
break
|
|
||||||
} else if arg == "-" {
|
|
||||||
// Do nothing. A dash alone is not really a flag.
|
|
||||||
continue
|
|
||||||
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
|
|
||||||
firstFlagIndex = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if firstFlagIndex > -1 {
|
|
||||||
args := ctx.Args()
|
|
||||||
regularArgs := make([]string, len(args[1:firstFlagIndex]))
|
|
||||||
copy(regularArgs, args[1:firstFlagIndex])
|
|
||||||
|
|
||||||
var flagArgs []string
|
|
||||||
if terminatorIndex > -1 {
|
|
||||||
flagArgs = args[firstFlagIndex:terminatorIndex]
|
|
||||||
regularArgs = append(regularArgs, args[terminatorIndex:]...)
|
|
||||||
} else {
|
|
||||||
flagArgs = args[firstFlagIndex:]
|
|
||||||
}
|
|
||||||
|
|
||||||
err = set.Parse(append(flagArgs, regularArgs...))
|
|
||||||
} else {
|
|
||||||
err = set.Parse(ctx.Args().Tail())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = set.Parse(ctx.Args().Tail())
|
|
||||||
}
|
|
||||||
|
|
||||||
nerr := normalizeFlags(c.Flags, set)
|
|
||||||
if nerr != nil {
|
|
||||||
fmt.Fprintln(ctx.App.Writer, nerr)
|
|
||||||
fmt.Fprintln(ctx.App.Writer)
|
|
||||||
ShowCommandHelp(ctx, c.Name)
|
|
||||||
return nerr
|
|
||||||
}
|
|
||||||
|
|
||||||
context := NewContext(ctx.App, set, ctx)
|
|
||||||
context.Command = c
|
|
||||||
if checkCommandCompletions(context, c.Name) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if c.OnUsageError != nil {
|
|
||||||
err := c.OnUsageError(context, err, false)
|
|
||||||
HandleExitCoder(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error())
|
|
||||||
fmt.Fprintln(context.App.Writer)
|
|
||||||
ShowCommandHelp(context, c.Name)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if checkCommandHelp(context, c.Name) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.After != nil {
|
|
||||||
defer func() {
|
|
||||||
afterErr := c.After(context)
|
|
||||||
if afterErr != nil {
|
|
||||||
HandleExitCoder(err)
|
|
||||||
if err != nil {
|
|
||||||
err = NewMultiError(err, afterErr)
|
|
||||||
} else {
|
|
||||||
err = afterErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Before != nil {
|
|
||||||
err = c.Before(context)
|
|
||||||
if err != nil {
|
|
||||||
ShowCommandHelp(context, c.Name)
|
|
||||||
HandleExitCoder(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Action == nil {
|
|
||||||
c.Action = helpSubcommand.Action
|
|
||||||
}
|
|
||||||
|
|
||||||
err = HandleAction(c.Action, context)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
HandleExitCoder(err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Names returns the names including short names and aliases.
|
|
||||||
func (c Command) Names() []string {
|
|
||||||
names := []string{c.Name}
|
|
||||||
|
|
||||||
if c.ShortName != "" {
|
|
||||||
names = append(names, c.ShortName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return append(names, c.Aliases...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasName returns true if Command.Name or Command.ShortName matches given name
|
|
||||||
func (c Command) HasName(name string) bool {
|
|
||||||
for _, n := range c.Names() {
|
|
||||||
if n == name {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Command) startApp(ctx *Context) error {
|
|
||||||
app := NewApp()
|
|
||||||
app.Metadata = ctx.App.Metadata
|
|
||||||
// set the name and usage
|
|
||||||
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
|
|
||||||
if c.HelpName == "" {
|
|
||||||
app.HelpName = c.HelpName
|
|
||||||
} else {
|
|
||||||
app.HelpName = app.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Usage = c.Usage
|
|
||||||
app.Description = c.Description
|
|
||||||
app.ArgsUsage = c.ArgsUsage
|
|
||||||
|
|
||||||
// set CommandNotFound
|
|
||||||
app.CommandNotFound = ctx.App.CommandNotFound
|
|
||||||
app.CustomAppHelpTemplate = c.CustomHelpTemplate
|
|
||||||
|
|
||||||
// set the flags and commands
|
|
||||||
app.Commands = c.Subcommands
|
|
||||||
app.Flags = c.Flags
|
|
||||||
app.HideHelp = c.HideHelp
|
|
||||||
|
|
||||||
app.Version = ctx.App.Version
|
|
||||||
app.HideVersion = ctx.App.HideVersion
|
|
||||||
app.Compiled = ctx.App.Compiled
|
|
||||||
app.Author = ctx.App.Author
|
|
||||||
app.Email = ctx.App.Email
|
|
||||||
app.Writer = ctx.App.Writer
|
|
||||||
app.ErrWriter = ctx.App.ErrWriter
|
|
||||||
|
|
||||||
app.categories = CommandCategories{}
|
|
||||||
for _, command := range c.Subcommands {
|
|
||||||
app.categories = app.categories.AddCommand(command.Category, command)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Sort(app.categories)
|
|
||||||
|
|
||||||
// bash completion
|
|
||||||
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
|
||||||
if c.BashComplete != nil {
|
|
||||||
app.BashComplete = c.BashComplete
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the actions
|
|
||||||
app.Before = c.Before
|
|
||||||
app.After = c.After
|
|
||||||
if c.Action != nil {
|
|
||||||
app.Action = c.Action
|
|
||||||
} else {
|
|
||||||
app.Action = helpSubcommand.Action
|
|
||||||
}
|
|
||||||
app.OnUsageError = c.OnUsageError
|
|
||||||
|
|
||||||
for index, cc := range app.Commands {
|
|
||||||
app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
|
|
||||||
}
|
|
||||||
|
|
||||||
return app.RunAsSubcommand(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
|
||||||
func (c Command) VisibleFlags() []Flag {
|
|
||||||
return visibleFlags(c.Flags)
|
|
||||||
}
|
|
278
vendor/github.com/urfave/cli/context.go
generated
vendored
278
vendor/github.com/urfave/cli/context.go
generated
vendored
@ -1,278 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"flag"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Context is a type that is passed through to
|
|
||||||
// each Handler action in a cli application. Context
|
|
||||||
// can be used to retrieve context-specific Args and
|
|
||||||
// parsed command-line options.
|
|
||||||
type Context struct {
|
|
||||||
App *App
|
|
||||||
Command Command
|
|
||||||
shellComplete bool
|
|
||||||
flagSet *flag.FlagSet
|
|
||||||
setFlags map[string]bool
|
|
||||||
parentContext *Context
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContext creates a new context. For use in when invoking an App or Command action.
|
|
||||||
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
|
|
||||||
c := &Context{App: app, flagSet: set, parentContext: parentCtx}
|
|
||||||
|
|
||||||
if parentCtx != nil {
|
|
||||||
c.shellComplete = parentCtx.shellComplete
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// NumFlags returns the number of flags set
|
|
||||||
func (c *Context) NumFlags() int {
|
|
||||||
return c.flagSet.NFlag()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set sets a context flag to a value.
|
|
||||||
func (c *Context) Set(name, value string) error {
|
|
||||||
c.setFlags = nil
|
|
||||||
return c.flagSet.Set(name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalSet sets a context flag to a value on the global flagset
|
|
||||||
func (c *Context) GlobalSet(name, value string) error {
|
|
||||||
globalContext(c).setFlags = nil
|
|
||||||
return globalContext(c).flagSet.Set(name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSet determines if the flag was actually set
|
|
||||||
func (c *Context) IsSet(name string) bool {
|
|
||||||
if c.setFlags == nil {
|
|
||||||
c.setFlags = make(map[string]bool)
|
|
||||||
|
|
||||||
c.flagSet.Visit(func(f *flag.Flag) {
|
|
||||||
c.setFlags[f.Name] = true
|
|
||||||
})
|
|
||||||
|
|
||||||
c.flagSet.VisitAll(func(f *flag.Flag) {
|
|
||||||
if _, ok := c.setFlags[f.Name]; ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.setFlags[f.Name] = false
|
|
||||||
})
|
|
||||||
|
|
||||||
// XXX hack to support IsSet for flags with EnvVar
|
|
||||||
//
|
|
||||||
// There isn't an easy way to do this with the current implementation since
|
|
||||||
// whether a flag was set via an environment variable is very difficult to
|
|
||||||
// determine here. Instead, we intend to introduce a backwards incompatible
|
|
||||||
// change in version 2 to add `IsSet` to the Flag interface to push the
|
|
||||||
// responsibility closer to where the information required to determine
|
|
||||||
// whether a flag is set by non-standard means such as environment
|
|
||||||
// variables is avaliable.
|
|
||||||
//
|
|
||||||
// See https://github.com/urfave/cli/issues/294 for additional discussion
|
|
||||||
flags := c.Command.Flags
|
|
||||||
if c.Command.Name == "" { // cannot == Command{} since it contains slice types
|
|
||||||
if c.App != nil {
|
|
||||||
flags = c.App.Flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, f := range flags {
|
|
||||||
eachName(f.GetName(), func(name string) {
|
|
||||||
if isSet, ok := c.setFlags[name]; isSet || !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val := reflect.ValueOf(f)
|
|
||||||
if val.Kind() == reflect.Ptr {
|
|
||||||
val = val.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
envVarValue := val.FieldByName("EnvVar")
|
|
||||||
if !envVarValue.IsValid() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(envVarValue.String(), func(envVar string) {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if _, ok := syscall.Getenv(envVar); ok {
|
|
||||||
c.setFlags[name] = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.setFlags[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalIsSet determines if the global flag was actually set
|
|
||||||
func (c *Context) GlobalIsSet(name string) bool {
|
|
||||||
ctx := c
|
|
||||||
if ctx.parentContext != nil {
|
|
||||||
ctx = ctx.parentContext
|
|
||||||
}
|
|
||||||
|
|
||||||
for ; ctx != nil; ctx = ctx.parentContext {
|
|
||||||
if ctx.IsSet(name) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlagNames returns a slice of flag names used in this context.
|
|
||||||
func (c *Context) FlagNames() (names []string) {
|
|
||||||
for _, flag := range c.Command.Flags {
|
|
||||||
name := strings.Split(flag.GetName(), ",")[0]
|
|
||||||
if name == "help" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
names = append(names, name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalFlagNames returns a slice of global flag names used by the app.
|
|
||||||
func (c *Context) GlobalFlagNames() (names []string) {
|
|
||||||
for _, flag := range c.App.Flags {
|
|
||||||
name := strings.Split(flag.GetName(), ",")[0]
|
|
||||||
if name == "help" || name == "version" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
names = append(names, name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parent returns the parent context, if any
|
|
||||||
func (c *Context) Parent() *Context {
|
|
||||||
return c.parentContext
|
|
||||||
}
|
|
||||||
|
|
||||||
// value returns the value of the flag coressponding to `name`
|
|
||||||
func (c *Context) value(name string) interface{} {
|
|
||||||
return c.flagSet.Lookup(name).Value.(flag.Getter).Get()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Args contains apps console arguments
|
|
||||||
type Args []string
|
|
||||||
|
|
||||||
// Args returns the command line arguments associated with the context.
|
|
||||||
func (c *Context) Args() Args {
|
|
||||||
args := Args(c.flagSet.Args())
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
// NArg returns the number of the command line arguments.
|
|
||||||
func (c *Context) NArg() int {
|
|
||||||
return len(c.Args())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the nth argument, or else a blank string
|
|
||||||
func (a Args) Get(n int) string {
|
|
||||||
if len(a) > n {
|
|
||||||
return a[n]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// First returns the first argument, or else a blank string
|
|
||||||
func (a Args) First() string {
|
|
||||||
return a.Get(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tail returns the rest of the arguments (not the first one)
|
|
||||||
// or else an empty string slice
|
|
||||||
func (a Args) Tail() []string {
|
|
||||||
if len(a) >= 2 {
|
|
||||||
return []string(a)[1:]
|
|
||||||
}
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Present checks if there are any arguments present
|
|
||||||
func (a Args) Present() bool {
|
|
||||||
return len(a) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap swaps arguments at the given indexes
|
|
||||||
func (a Args) Swap(from, to int) error {
|
|
||||||
if from >= len(a) || to >= len(a) {
|
|
||||||
return errors.New("index out of range")
|
|
||||||
}
|
|
||||||
a[from], a[to] = a[to], a[from]
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func globalContext(ctx *Context) *Context {
|
|
||||||
if ctx == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
if ctx.parentContext == nil {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
ctx = ctx.parentContext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
|
|
||||||
if ctx.parentContext != nil {
|
|
||||||
ctx = ctx.parentContext
|
|
||||||
}
|
|
||||||
for ; ctx != nil; ctx = ctx.parentContext {
|
|
||||||
if f := ctx.flagSet.Lookup(name); f != nil {
|
|
||||||
return ctx.flagSet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
|
|
||||||
switch ff.Value.(type) {
|
|
||||||
case *StringSlice:
|
|
||||||
default:
|
|
||||||
set.Set(name, ff.Value.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
|
|
||||||
visited := make(map[string]bool)
|
|
||||||
set.Visit(func(f *flag.Flag) {
|
|
||||||
visited[f.Name] = true
|
|
||||||
})
|
|
||||||
for _, f := range flags {
|
|
||||||
parts := strings.Split(f.GetName(), ",")
|
|
||||||
if len(parts) == 1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var ff *flag.Flag
|
|
||||||
for _, name := range parts {
|
|
||||||
name = strings.Trim(name, " ")
|
|
||||||
if visited[name] {
|
|
||||||
if ff != nil {
|
|
||||||
return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
|
|
||||||
}
|
|
||||||
ff = set.Lookup(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ff == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, name := range parts {
|
|
||||||
name = strings.Trim(name, " ")
|
|
||||||
if !visited[name] {
|
|
||||||
copyFlag(name, ff, set)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
115
vendor/github.com/urfave/cli/errors.go
generated
vendored
115
vendor/github.com/urfave/cli/errors.go
generated
vendored
@ -1,115 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OsExiter is the function used when the app exits. If not set defaults to os.Exit.
|
|
||||||
var OsExiter = os.Exit
|
|
||||||
|
|
||||||
// ErrWriter is used to write errors to the user. This can be anything
|
|
||||||
// implementing the io.Writer interface and defaults to os.Stderr.
|
|
||||||
var ErrWriter io.Writer = os.Stderr
|
|
||||||
|
|
||||||
// MultiError is an error that wraps multiple errors.
|
|
||||||
type MultiError struct {
|
|
||||||
Errors []error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMultiError creates a new MultiError. Pass in one or more errors.
|
|
||||||
func NewMultiError(err ...error) MultiError {
|
|
||||||
return MultiError{Errors: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements the error interface.
|
|
||||||
func (m MultiError) Error() string {
|
|
||||||
errs := make([]string, len(m.Errors))
|
|
||||||
for i, err := range m.Errors {
|
|
||||||
errs[i] = err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(errs, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrorFormatter interface {
|
|
||||||
Format(s fmt.State, verb rune)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitCoder is the interface checked by `App` and `Command` for a custom exit
|
|
||||||
// code
|
|
||||||
type ExitCoder interface {
|
|
||||||
error
|
|
||||||
ExitCode() int
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitError fulfills both the builtin `error` interface and `ExitCoder`
|
|
||||||
type ExitError struct {
|
|
||||||
exitCode int
|
|
||||||
message interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewExitError makes a new *ExitError
|
|
||||||
func NewExitError(message interface{}, exitCode int) *ExitError {
|
|
||||||
return &ExitError{
|
|
||||||
exitCode: exitCode,
|
|
||||||
message: message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error returns the string message, fulfilling the interface required by
|
|
||||||
// `error`
|
|
||||||
func (ee *ExitError) Error() string {
|
|
||||||
return fmt.Sprintf("%v", ee.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExitCode returns the exit code, fulfilling the interface required by
|
|
||||||
// `ExitCoder`
|
|
||||||
func (ee *ExitError) ExitCode() int {
|
|
||||||
return ee.exitCode
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
|
|
||||||
// so prints the error to stderr (if it is non-empty) and calls OsExiter with the
|
|
||||||
// given exit code. If the given error is a MultiError, then this func is
|
|
||||||
// called on all members of the Errors slice and calls OsExiter with the last exit code.
|
|
||||||
func HandleExitCoder(err error) {
|
|
||||||
if err == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if exitErr, ok := err.(ExitCoder); ok {
|
|
||||||
if err.Error() != "" {
|
|
||||||
if _, ok := exitErr.(ErrorFormatter); ok {
|
|
||||||
fmt.Fprintf(ErrWriter, "%+v\n", err)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(ErrWriter, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OsExiter(exitErr.ExitCode())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if multiErr, ok := err.(MultiError); ok {
|
|
||||||
code := handleMultiError(multiErr)
|
|
||||||
OsExiter(code)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMultiError(multiErr MultiError) int {
|
|
||||||
code := 1
|
|
||||||
for _, merr := range multiErr.Errors {
|
|
||||||
if multiErr2, ok := merr.(MultiError); ok {
|
|
||||||
code = handleMultiError(multiErr2)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(ErrWriter, merr)
|
|
||||||
if exitErr, ok := merr.(ExitCoder); ok {
|
|
||||||
code = exitErr.ExitCode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return code
|
|
||||||
}
|
|
93
vendor/github.com/urfave/cli/flag-types.json
generated
vendored
93
vendor/github.com/urfave/cli/flag-types.json
generated
vendored
@ -1,93 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "Bool",
|
|
||||||
"type": "bool",
|
|
||||||
"value": false,
|
|
||||||
"context_default": "false",
|
|
||||||
"parser": "strconv.ParseBool(f.Value.String())"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "BoolT",
|
|
||||||
"type": "bool",
|
|
||||||
"value": false,
|
|
||||||
"doctail": " that is true by default",
|
|
||||||
"context_default": "false",
|
|
||||||
"parser": "strconv.ParseBool(f.Value.String())"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Duration",
|
|
||||||
"type": "time.Duration",
|
|
||||||
"doctail": " (see https://golang.org/pkg/time/#ParseDuration)",
|
|
||||||
"context_default": "0",
|
|
||||||
"parser": "time.ParseDuration(f.Value.String())"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Float64",
|
|
||||||
"type": "float64",
|
|
||||||
"context_default": "0",
|
|
||||||
"parser": "strconv.ParseFloat(f.Value.String(), 64)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic",
|
|
||||||
"type": "Generic",
|
|
||||||
"dest": false,
|
|
||||||
"context_default": "nil",
|
|
||||||
"context_type": "interface{}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Int64",
|
|
||||||
"type": "int64",
|
|
||||||
"context_default": "0",
|
|
||||||
"parser": "strconv.ParseInt(f.Value.String(), 0, 64)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Int",
|
|
||||||
"type": "int",
|
|
||||||
"context_default": "0",
|
|
||||||
"parser": "strconv.ParseInt(f.Value.String(), 0, 64)",
|
|
||||||
"parser_cast": "int(parsed)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "IntSlice",
|
|
||||||
"type": "*IntSlice",
|
|
||||||
"dest": false,
|
|
||||||
"context_default": "nil",
|
|
||||||
"context_type": "[]int",
|
|
||||||
"parser": "(f.Value.(*IntSlice)).Value(), error(nil)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Int64Slice",
|
|
||||||
"type": "*Int64Slice",
|
|
||||||
"dest": false,
|
|
||||||
"context_default": "nil",
|
|
||||||
"context_type": "[]int64",
|
|
||||||
"parser": "(f.Value.(*Int64Slice)).Value(), error(nil)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "String",
|
|
||||||
"type": "string",
|
|
||||||
"context_default": "\"\"",
|
|
||||||
"parser": "f.Value.String(), error(nil)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "StringSlice",
|
|
||||||
"type": "*StringSlice",
|
|
||||||
"dest": false,
|
|
||||||
"context_default": "nil",
|
|
||||||
"context_type": "[]string",
|
|
||||||
"parser": "(f.Value.(*StringSlice)).Value(), error(nil)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Uint64",
|
|
||||||
"type": "uint64",
|
|
||||||
"context_default": "0",
|
|
||||||
"parser": "strconv.ParseUint(f.Value.String(), 0, 64)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Uint",
|
|
||||||
"type": "uint",
|
|
||||||
"context_default": "0",
|
|
||||||
"parser": "strconv.ParseUint(f.Value.String(), 0, 64)",
|
|
||||||
"parser_cast": "uint(parsed)"
|
|
||||||
}
|
|
||||||
]
|
|
799
vendor/github.com/urfave/cli/flag.go
generated
vendored
799
vendor/github.com/urfave/cli/flag.go
generated
vendored
@ -1,799 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const defaultPlaceholder = "value"
|
|
||||||
|
|
||||||
// BashCompletionFlag enables bash-completion for all commands and subcommands
|
|
||||||
var BashCompletionFlag Flag = BoolFlag{
|
|
||||||
Name: "generate-bash-completion",
|
|
||||||
Hidden: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// VersionFlag prints the version for the application
|
|
||||||
var VersionFlag Flag = BoolFlag{
|
|
||||||
Name: "version, v",
|
|
||||||
Usage: "print the version",
|
|
||||||
}
|
|
||||||
|
|
||||||
// HelpFlag prints the help for all commands and subcommands
|
|
||||||
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
|
|
||||||
// unless HideHelp is set to true)
|
|
||||||
var HelpFlag Flag = BoolFlag{
|
|
||||||
Name: "help, h",
|
|
||||||
Usage: "show help",
|
|
||||||
}
|
|
||||||
|
|
||||||
// FlagStringer converts a flag definition to a string. This is used by help
|
|
||||||
// to display a flag.
|
|
||||||
var FlagStringer FlagStringFunc = stringifyFlag
|
|
||||||
|
|
||||||
// FlagsByName is a slice of Flag.
|
|
||||||
type FlagsByName []Flag
|
|
||||||
|
|
||||||
func (f FlagsByName) Len() int {
|
|
||||||
return len(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FlagsByName) Less(i, j int) bool {
|
|
||||||
return f[i].GetName() < f[j].GetName()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FlagsByName) Swap(i, j int) {
|
|
||||||
f[i], f[j] = f[j], f[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flag is a common interface related to parsing flags in cli.
|
|
||||||
// For more advanced flag parsing techniques, it is recommended that
|
|
||||||
// this interface be implemented.
|
|
||||||
type Flag interface {
|
|
||||||
fmt.Stringer
|
|
||||||
// Apply Flag settings to the given flag set
|
|
||||||
Apply(*flag.FlagSet)
|
|
||||||
GetName() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// errorableFlag is an interface that allows us to return errors during apply
|
|
||||||
// it allows flags defined in this library to return errors in a fashion backwards compatible
|
|
||||||
// TODO remove in v2 and modify the existing Flag interface to return errors
|
|
||||||
type errorableFlag interface {
|
|
||||||
Flag
|
|
||||||
|
|
||||||
ApplyWithError(*flag.FlagSet) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
|
|
||||||
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
|
||||||
|
|
||||||
for _, f := range flags {
|
|
||||||
//TODO remove in v2 when errorableFlag is removed
|
|
||||||
if ef, ok := f.(errorableFlag); ok {
|
|
||||||
if err := ef.ApplyWithError(set); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
f.Apply(set)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return set, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func eachName(longName string, fn func(string)) {
|
|
||||||
parts := strings.Split(longName, ",")
|
|
||||||
for _, name := range parts {
|
|
||||||
name = strings.Trim(name, " ")
|
|
||||||
fn(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic is a generic parseable type identified by a specific flag
|
|
||||||
type Generic interface {
|
|
||||||
Set(value string) error
|
|
||||||
String() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply takes the flagset and calls Set on the generic flag with the value
|
|
||||||
// provided by the user for parsing by the flag
|
|
||||||
// Ignores parsing errors
|
|
||||||
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError takes the flagset and calls Set on the generic flag with the value
|
|
||||||
// provided by the user for parsing by the flag
|
|
||||||
func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
val := f.Value
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
if err := val.Set(envVal); err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
set.Var(f.Value, name, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter
|
|
||||||
type StringSlice []string
|
|
||||||
|
|
||||||
// Set appends the string value to the list of values
|
|
||||||
func (f *StringSlice) Set(value string) error {
|
|
||||||
*f = append(*f, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
|
||||||
func (f *StringSlice) String() string {
|
|
||||||
return fmt.Sprintf("%s", *f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the slice of strings set by this flag
|
|
||||||
func (f *StringSlice) Value() []string {
|
|
||||||
return *f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the slice of strings set by this flag
|
|
||||||
func (f *StringSlice) Get() interface{} {
|
|
||||||
return *f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
newVal := &StringSlice{}
|
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
if err := newVal.Set(s); err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Value = newVal
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Value == nil {
|
|
||||||
f.Value = &StringSlice{}
|
|
||||||
}
|
|
||||||
set.Var(f.Value, name, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter
|
|
||||||
type IntSlice []int
|
|
||||||
|
|
||||||
// Set parses the value into an integer and appends it to the list of values
|
|
||||||
func (f *IntSlice) Set(value string) error {
|
|
||||||
tmp, err := strconv.Atoi(value)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*f = append(*f, tmp)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
|
||||||
func (f *IntSlice) String() string {
|
|
||||||
return fmt.Sprintf("%#v", *f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the slice of ints set by this flag
|
|
||||||
func (f *IntSlice) Value() []int {
|
|
||||||
return *f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the slice of ints set by this flag
|
|
||||||
func (f *IntSlice) Get() interface{} {
|
|
||||||
return *f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
newVal := &IntSlice{}
|
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
if err := newVal.Set(s); err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Value = newVal
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Value == nil {
|
|
||||||
f.Value = &IntSlice{}
|
|
||||||
}
|
|
||||||
set.Var(f.Value, name, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter
|
|
||||||
type Int64Slice []int64
|
|
||||||
|
|
||||||
// Set parses the value into an integer and appends it to the list of values
|
|
||||||
func (f *Int64Slice) Set(value string) error {
|
|
||||||
tmp, err := strconv.ParseInt(value, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*f = append(*f, tmp)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
|
||||||
func (f *Int64Slice) String() string {
|
|
||||||
return fmt.Sprintf("%#v", *f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value returns the slice of ints set by this flag
|
|
||||||
func (f *Int64Slice) Value() []int64 {
|
|
||||||
return *f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the slice of ints set by this flag
|
|
||||||
func (f *Int64Slice) Get() interface{} {
|
|
||||||
return *f
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
newVal := &Int64Slice{}
|
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
|
||||||
s = strings.TrimSpace(s)
|
|
||||||
if err := newVal.Set(s); err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Value = newVal
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Value == nil {
|
|
||||||
f.Value = &Int64Slice{}
|
|
||||||
}
|
|
||||||
set.Var(f.Value, name, f.Usage)
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
val := false
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
if envVal == "" {
|
|
||||||
val = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
envValBool, err := strconv.ParseBool(envVal)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
val = envValBool
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.BoolVar(f.Destination, name, val, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Bool(name, val, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
val := true
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
if envVal == "" {
|
|
||||||
val = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
envValBool, err := strconv.ParseBool(envVal)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
val = envValBool
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.BoolVar(f.Destination, name, val, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Bool(name, val, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f StringFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f StringFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
f.Value = envVal
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.StringVar(f.Destination, name, f.Value, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.String(name, f.Value, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f IntFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f IntFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
f.Value = int(envValInt)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.IntVar(f.Destination, name, f.Value, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Int(name, f.Value, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f Int64Flag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Value = envValInt
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.Int64Var(f.Destination, name, f.Value, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Int64(name, f.Value, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f UintFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f UintFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Value = uint(envValInt)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.UintVar(f.Destination, name, f.Value, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Uint(name, f.Value, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f Uint64Flag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Value = uint64(envValInt)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.Uint64Var(f.Destination, name, f.Value, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Uint64(name, f.Value, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
envValDuration, err := time.ParseDuration(envVal)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Value = envValDuration
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.DurationVar(f.Destination, name, f.Value, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Duration(name, f.Value, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
|
||||||
// Ignores errors
|
|
||||||
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
|
||||||
f.ApplyWithError(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyWithError populates the flag given the flag set and environment
|
|
||||||
func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error {
|
|
||||||
if f.EnvVar != "" {
|
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal, ok := syscall.Getenv(envVar); ok {
|
|
||||||
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Value = float64(envValFloat)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
|
||||||
if f.Destination != nil {
|
|
||||||
set.Float64Var(f.Destination, name, f.Value, f.Usage)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
set.Float64(name, f.Value, f.Usage)
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func visibleFlags(fl []Flag) []Flag {
|
|
||||||
visible := []Flag{}
|
|
||||||
for _, flag := range fl {
|
|
||||||
field := flagValue(flag).FieldByName("Hidden")
|
|
||||||
if !field.IsValid() || !field.Bool() {
|
|
||||||
visible = append(visible, flag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return visible
|
|
||||||
}
|
|
||||||
|
|
||||||
func prefixFor(name string) (prefix string) {
|
|
||||||
if len(name) == 1 {
|
|
||||||
prefix = "-"
|
|
||||||
} else {
|
|
||||||
prefix = "--"
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the placeholder, if any, and the unquoted usage string.
|
|
||||||
func unquoteUsage(usage string) (string, string) {
|
|
||||||
for i := 0; i < len(usage); i++ {
|
|
||||||
if usage[i] == '`' {
|
|
||||||
for j := i + 1; j < len(usage); j++ {
|
|
||||||
if usage[j] == '`' {
|
|
||||||
name := usage[i+1 : j]
|
|
||||||
usage = usage[:i] + name + usage[j+1:]
|
|
||||||
return name, usage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", usage
|
|
||||||
}
|
|
||||||
|
|
||||||
func prefixedNames(fullName, placeholder string) string {
|
|
||||||
var prefixed string
|
|
||||||
parts := strings.Split(fullName, ",")
|
|
||||||
for i, name := range parts {
|
|
||||||
name = strings.Trim(name, " ")
|
|
||||||
prefixed += prefixFor(name) + name
|
|
||||||
if placeholder != "" {
|
|
||||||
prefixed += " " + placeholder
|
|
||||||
}
|
|
||||||
if i < len(parts)-1 {
|
|
||||||
prefixed += ", "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prefixed
|
|
||||||
}
|
|
||||||
|
|
||||||
func withEnvHint(envVar, str string) string {
|
|
||||||
envText := ""
|
|
||||||
if envVar != "" {
|
|
||||||
prefix := "$"
|
|
||||||
suffix := ""
|
|
||||||
sep := ", $"
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
prefix = "%"
|
|
||||||
suffix = "%"
|
|
||||||
sep = "%, %"
|
|
||||||
}
|
|
||||||
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
|
|
||||||
}
|
|
||||||
return str + envText
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagValue(f Flag) reflect.Value {
|
|
||||||
fv := reflect.ValueOf(f)
|
|
||||||
for fv.Kind() == reflect.Ptr {
|
|
||||||
fv = reflect.Indirect(fv)
|
|
||||||
}
|
|
||||||
return fv
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringifyFlag(f Flag) string {
|
|
||||||
fv := flagValue(f)
|
|
||||||
|
|
||||||
switch f.(type) {
|
|
||||||
case IntSliceFlag:
|
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
||||||
stringifyIntSliceFlag(f.(IntSliceFlag)))
|
|
||||||
case Int64SliceFlag:
|
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
||||||
stringifyInt64SliceFlag(f.(Int64SliceFlag)))
|
|
||||||
case StringSliceFlag:
|
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
||||||
stringifyStringSliceFlag(f.(StringSliceFlag)))
|
|
||||||
}
|
|
||||||
|
|
||||||
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
|
|
||||||
|
|
||||||
needsPlaceholder := false
|
|
||||||
defaultValueString := ""
|
|
||||||
|
|
||||||
if val := fv.FieldByName("Value"); val.IsValid() {
|
|
||||||
needsPlaceholder = true
|
|
||||||
defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
|
|
||||||
|
|
||||||
if val.Kind() == reflect.String && val.String() != "" {
|
|
||||||
defaultValueString = fmt.Sprintf(" (default: %q)", val.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if defaultValueString == " (default: )" {
|
|
||||||
defaultValueString = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if needsPlaceholder && placeholder == "" {
|
|
||||||
placeholder = defaultPlaceholder
|
|
||||||
}
|
|
||||||
|
|
||||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
|
|
||||||
|
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
||||||
fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault))
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringifyIntSliceFlag(f IntSliceFlag) string {
|
|
||||||
defaultVals := []string{}
|
|
||||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
|
||||||
for _, i := range f.Value.Value() {
|
|
||||||
defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringifyInt64SliceFlag(f Int64SliceFlag) string {
|
|
||||||
defaultVals := []string{}
|
|
||||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
|
||||||
for _, i := range f.Value.Value() {
|
|
||||||
defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringifyStringSliceFlag(f StringSliceFlag) string {
|
|
||||||
defaultVals := []string{}
|
|
||||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
|
||||||
for _, s := range f.Value.Value() {
|
|
||||||
if len(s) > 0 {
|
|
||||||
defaultVals = append(defaultVals, fmt.Sprintf("%q", s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringifySliceFlag(usage, name string, defaultVals []string) string {
|
|
||||||
placeholder, usage := unquoteUsage(usage)
|
|
||||||
if placeholder == "" {
|
|
||||||
placeholder = defaultPlaceholder
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultVal := ""
|
|
||||||
if len(defaultVals) > 0 {
|
|
||||||
defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
|
||||||
return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault)
|
|
||||||
}
|
|
627
vendor/github.com/urfave/cli/flag_generated.go
generated
vendored
627
vendor/github.com/urfave/cli/flag_generated.go
generated
vendored
@ -1,627 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WARNING: This file is generated!
|
|
||||||
|
|
||||||
// BoolFlag is a flag with type bool
|
|
||||||
type BoolFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Destination *bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f BoolFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f BoolFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool looks up the value of a local BoolFlag, returns
|
|
||||||
// false if not found
|
|
||||||
func (c *Context) Bool(name string) bool {
|
|
||||||
return lookupBool(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalBool looks up the value of a global BoolFlag, returns
|
|
||||||
// false if not found
|
|
||||||
func (c *Context) GlobalBool(name string) bool {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupBool(name, fs)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupBool(name string, set *flag.FlagSet) bool {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := strconv.ParseBool(f.Value.String())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolTFlag is a flag with type bool that is true by default
|
|
||||||
type BoolTFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Destination *bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f BoolTFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f BoolTFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolT looks up the value of a local BoolTFlag, returns
|
|
||||||
// false if not found
|
|
||||||
func (c *Context) BoolT(name string) bool {
|
|
||||||
return lookupBoolT(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalBoolT looks up the value of a global BoolTFlag, returns
|
|
||||||
// false if not found
|
|
||||||
func (c *Context) GlobalBoolT(name string) bool {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupBoolT(name, fs)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupBoolT(name string, set *flag.FlagSet) bool {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := strconv.ParseBool(f.Value.String())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration)
|
|
||||||
type DurationFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value time.Duration
|
|
||||||
Destination *time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f DurationFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f DurationFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duration looks up the value of a local DurationFlag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) Duration(name string) time.Duration {
|
|
||||||
return lookupDuration(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalDuration looks up the value of a global DurationFlag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) GlobalDuration(name string) time.Duration {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupDuration(name, fs)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupDuration(name string, set *flag.FlagSet) time.Duration {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := time.ParseDuration(f.Value.String())
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64Flag is a flag with type float64
|
|
||||||
type Float64Flag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value float64
|
|
||||||
Destination *float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f Float64Flag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f Float64Flag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64 looks up the value of a local Float64Flag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) Float64(name string) float64 {
|
|
||||||
return lookupFloat64(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalFloat64 looks up the value of a global Float64Flag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) GlobalFloat64(name string) float64 {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupFloat64(name, fs)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupFloat64(name string, set *flag.FlagSet) float64 {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := strconv.ParseFloat(f.Value.String(), 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenericFlag is a flag with type Generic
|
|
||||||
type GenericFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value Generic
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f GenericFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f GenericFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic looks up the value of a local GenericFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) Generic(name string) interface{} {
|
|
||||||
return lookupGeneric(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalGeneric looks up the value of a global GenericFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) GlobalGeneric(name string) interface{} {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupGeneric(name, fs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupGeneric(name string, set *flag.FlagSet) interface{} {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := f.Value, error(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64Flag is a flag with type int64
|
|
||||||
type Int64Flag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value int64
|
|
||||||
Destination *int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f Int64Flag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f Int64Flag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64 looks up the value of a local Int64Flag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) Int64(name string) int64 {
|
|
||||||
return lookupInt64(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalInt64 looks up the value of a global Int64Flag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) GlobalInt64(name string) int64 {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupInt64(name, fs)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupInt64(name string, set *flag.FlagSet) int64 {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntFlag is a flag with type int
|
|
||||||
type IntFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value int
|
|
||||||
Destination *int
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f IntFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f IntFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int looks up the value of a local IntFlag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) Int(name string) int {
|
|
||||||
return lookupInt(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalInt looks up the value of a global IntFlag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) GlobalInt(name string) int {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupInt(name, fs)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupInt(name string, set *flag.FlagSet) int {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return int(parsed)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntSliceFlag is a flag with type *IntSlice
|
|
||||||
type IntSliceFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value *IntSlice
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f IntSliceFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f IntSliceFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntSlice looks up the value of a local IntSliceFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) IntSlice(name string) []int {
|
|
||||||
return lookupIntSlice(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalIntSlice looks up the value of a global IntSliceFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) GlobalIntSlice(name string) []int {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupIntSlice(name, fs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupIntSlice(name string, set *flag.FlagSet) []int {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := (f.Value.(*IntSlice)).Value(), error(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64SliceFlag is a flag with type *Int64Slice
|
|
||||||
type Int64SliceFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value *Int64Slice
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f Int64SliceFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f Int64SliceFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Int64Slice looks up the value of a local Int64SliceFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) Int64Slice(name string) []int64 {
|
|
||||||
return lookupInt64Slice(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) GlobalInt64Slice(name string) []int64 {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupInt64Slice(name, fs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringFlag is a flag with type string
|
|
||||||
type StringFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value string
|
|
||||||
Destination *string
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f StringFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f StringFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// String looks up the value of a local StringFlag, returns
|
|
||||||
// "" if not found
|
|
||||||
func (c *Context) String(name string) string {
|
|
||||||
return lookupString(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalString looks up the value of a global StringFlag, returns
|
|
||||||
// "" if not found
|
|
||||||
func (c *Context) GlobalString(name string) string {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupString(name, fs)
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupString(name string, set *flag.FlagSet) string {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := f.Value.String(), error(nil)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringSliceFlag is a flag with type *StringSlice
|
|
||||||
type StringSliceFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value *StringSlice
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f StringSliceFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f StringSliceFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringSlice looks up the value of a local StringSliceFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) StringSlice(name string) []string {
|
|
||||||
return lookupStringSlice(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalStringSlice looks up the value of a global StringSliceFlag, returns
|
|
||||||
// nil if not found
|
|
||||||
func (c *Context) GlobalStringSlice(name string) []string {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupStringSlice(name, fs)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupStringSlice(name string, set *flag.FlagSet) []string {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := (f.Value.(*StringSlice)).Value(), error(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64Flag is a flag with type uint64
|
|
||||||
type Uint64Flag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value uint64
|
|
||||||
Destination *uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f Uint64Flag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f Uint64Flag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64 looks up the value of a local Uint64Flag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) Uint64(name string) uint64 {
|
|
||||||
return lookupUint64(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalUint64 looks up the value of a global Uint64Flag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) GlobalUint64(name string) uint64 {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupUint64(name, fs)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupUint64(name string, set *flag.FlagSet) uint64 {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return parsed
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// UintFlag is a flag with type uint
|
|
||||||
type UintFlag struct {
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
Value uint
|
|
||||||
Destination *uint
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f UintFlag) String() string {
|
|
||||||
return FlagStringer(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f UintFlag) GetName() string {
|
|
||||||
return f.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint looks up the value of a local UintFlag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) Uint(name string) uint {
|
|
||||||
return lookupUint(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalUint looks up the value of a global UintFlag, returns
|
|
||||||
// 0 if not found
|
|
||||||
func (c *Context) GlobalUint(name string) uint {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupUint(name, fs)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func lookupUint(name string, set *flag.FlagSet) uint {
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {
|
|
||||||
parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return uint(parsed)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
28
vendor/github.com/urfave/cli/funcs.go
generated
vendored
28
vendor/github.com/urfave/cli/funcs.go
generated
vendored
@ -1,28 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
// BashCompleteFunc is an action to execute when the bash-completion flag is set
|
|
||||||
type BashCompleteFunc func(*Context)
|
|
||||||
|
|
||||||
// BeforeFunc is an action to execute before any subcommands are run, but after
|
|
||||||
// the context is ready if a non-nil error is returned, no subcommands are run
|
|
||||||
type BeforeFunc func(*Context) error
|
|
||||||
|
|
||||||
// AfterFunc is an action to execute after any subcommands are run, but after the
|
|
||||||
// subcommand has finished it is run even if Action() panics
|
|
||||||
type AfterFunc func(*Context) error
|
|
||||||
|
|
||||||
// ActionFunc is the action to execute when no subcommands are specified
|
|
||||||
type ActionFunc func(*Context) error
|
|
||||||
|
|
||||||
// CommandNotFoundFunc is executed if the proper command cannot be found
|
|
||||||
type CommandNotFoundFunc func(*Context, string)
|
|
||||||
|
|
||||||
// OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying
|
|
||||||
// customized usage error messages. This function is able to replace the
|
|
||||||
// original error messages. If this function is not set, the "Incorrect usage"
|
|
||||||
// is displayed and the execution is interrupted.
|
|
||||||
type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error
|
|
||||||
|
|
||||||
// FlagStringFunc is used by the help generation to display a flag, which is
|
|
||||||
// expected to be a single line.
|
|
||||||
type FlagStringFunc func(Flag) string
|
|
255
vendor/github.com/urfave/cli/generate-flag-types
generated
vendored
255
vendor/github.com/urfave/cli/generate-flag-types
generated
vendored
@ -1,255 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""
|
|
||||||
The flag types that ship with the cli library have many things in common, and
|
|
||||||
so we can take advantage of the `go generate` command to create much of the
|
|
||||||
source code from a list of definitions. These definitions attempt to cover
|
|
||||||
the parts that vary between flag types, and should evolve as needed.
|
|
||||||
|
|
||||||
An example of the minimum definition needed is:
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "SomeType",
|
|
||||||
"type": "sometype",
|
|
||||||
"context_default": "nil"
|
|
||||||
}
|
|
||||||
|
|
||||||
In this example, the code generated for the `cli` package will include a type
|
|
||||||
named `SomeTypeFlag` that is expected to wrap a value of type `sometype`.
|
|
||||||
Fetching values by name via `*cli.Context` will default to a value of `nil`.
|
|
||||||
|
|
||||||
A more complete, albeit somewhat redundant, example showing all available
|
|
||||||
definition keys is:
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "VeryMuchType",
|
|
||||||
"type": "*VeryMuchType",
|
|
||||||
"value": true,
|
|
||||||
"dest": false,
|
|
||||||
"doctail": " which really only wraps a []float64, oh well!",
|
|
||||||
"context_type": "[]float64",
|
|
||||||
"context_default": "nil",
|
|
||||||
"parser": "parseVeryMuchType(f.Value.String())",
|
|
||||||
"parser_cast": "[]float64(parsed)"
|
|
||||||
}
|
|
||||||
|
|
||||||
The meaning of each field is as follows:
|
|
||||||
|
|
||||||
name (string) - The type "name", which will be suffixed with
|
|
||||||
`Flag` when generating the type definition
|
|
||||||
for `cli` and the wrapper type for `altsrc`
|
|
||||||
type (string) - The type that the generated `Flag` type for `cli`
|
|
||||||
is expected to "contain" as its `.Value` member
|
|
||||||
value (bool) - Should the generated `cli` type have a `Value`
|
|
||||||
member?
|
|
||||||
dest (bool) - Should the generated `cli` type support a
|
|
||||||
destination pointer?
|
|
||||||
doctail (string) - Additional docs for the `cli` flag type comment
|
|
||||||
context_type (string) - The literal type used in the `*cli.Context`
|
|
||||||
reader func signature
|
|
||||||
context_default (string) - The literal value used as the default by the
|
|
||||||
`*cli.Context` reader funcs when no value is
|
|
||||||
present
|
|
||||||
parser (string) - Literal code used to parse the flag `f`,
|
|
||||||
expected to have a return signature of
|
|
||||||
(value, error)
|
|
||||||
parser_cast (string) - Literal code used to cast the `parsed` value
|
|
||||||
returned from the `parser` code
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function, unicode_literals
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
import textwrap
|
|
||||||
|
|
||||||
|
|
||||||
class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter,
|
|
||||||
argparse.RawDescriptionHelpFormatter):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def main(sysargs=sys.argv[:]):
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description='Generate flag type code!',
|
|
||||||
formatter_class=_FancyFormatter)
|
|
||||||
parser.add_argument(
|
|
||||||
'package',
|
|
||||||
type=str, default='cli', choices=_WRITEFUNCS.keys(),
|
|
||||||
help='Package for which flag types will be generated'
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-i', '--in-json',
|
|
||||||
type=argparse.FileType('r'),
|
|
||||||
default=sys.stdin,
|
|
||||||
help='Input JSON file which defines each type to be generated'
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
'-o', '--out-go',
|
|
||||||
type=argparse.FileType('w'),
|
|
||||||
default=sys.stdout,
|
|
||||||
help='Output file/stream to which generated source will be written'
|
|
||||||
)
|
|
||||||
parser.epilog = __doc__
|
|
||||||
|
|
||||||
args = parser.parse_args(sysargs[1:])
|
|
||||||
_generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def _generate_flag_types(writefunc, output_go, input_json):
|
|
||||||
types = json.load(input_json)
|
|
||||||
|
|
||||||
tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False)
|
|
||||||
writefunc(tmp, types)
|
|
||||||
tmp.close()
|
|
||||||
|
|
||||||
new_content = subprocess.check_output(
|
|
||||||
['goimports', tmp.name]
|
|
||||||
).decode('utf-8')
|
|
||||||
|
|
||||||
print(new_content, file=output_go, end='')
|
|
||||||
output_go.flush()
|
|
||||||
os.remove(tmp.name)
|
|
||||||
|
|
||||||
|
|
||||||
def _set_typedef_defaults(typedef):
|
|
||||||
typedef.setdefault('doctail', '')
|
|
||||||
typedef.setdefault('context_type', typedef['type'])
|
|
||||||
typedef.setdefault('dest', True)
|
|
||||||
typedef.setdefault('value', True)
|
|
||||||
typedef.setdefault('parser', 'f.Value, error(nil)')
|
|
||||||
typedef.setdefault('parser_cast', 'parsed')
|
|
||||||
|
|
||||||
|
|
||||||
def _write_cli_flag_types(outfile, types):
|
|
||||||
_fwrite(outfile, """\
|
|
||||||
package cli
|
|
||||||
|
|
||||||
// WARNING: This file is generated!
|
|
||||||
|
|
||||||
""")
|
|
||||||
|
|
||||||
for typedef in types:
|
|
||||||
_set_typedef_defaults(typedef)
|
|
||||||
|
|
||||||
_fwrite(outfile, """\
|
|
||||||
// {name}Flag is a flag with type {type}{doctail}
|
|
||||||
type {name}Flag struct {{
|
|
||||||
Name string
|
|
||||||
Usage string
|
|
||||||
EnvVar string
|
|
||||||
Hidden bool
|
|
||||||
""".format(**typedef))
|
|
||||||
|
|
||||||
if typedef['value']:
|
|
||||||
_fwrite(outfile, """\
|
|
||||||
Value {type}
|
|
||||||
""".format(**typedef))
|
|
||||||
|
|
||||||
if typedef['dest']:
|
|
||||||
_fwrite(outfile, """\
|
|
||||||
Destination *{type}
|
|
||||||
""".format(**typedef))
|
|
||||||
|
|
||||||
_fwrite(outfile, "\n}\n\n")
|
|
||||||
|
|
||||||
_fwrite(outfile, """\
|
|
||||||
// String returns a readable representation of this value
|
|
||||||
// (for usage defaults)
|
|
||||||
func (f {name}Flag) String() string {{
|
|
||||||
return FlagStringer(f)
|
|
||||||
}}
|
|
||||||
|
|
||||||
// GetName returns the name of the flag
|
|
||||||
func (f {name}Flag) GetName() string {{
|
|
||||||
return f.Name
|
|
||||||
}}
|
|
||||||
|
|
||||||
// {name} looks up the value of a local {name}Flag, returns
|
|
||||||
// {context_default} if not found
|
|
||||||
func (c *Context) {name}(name string) {context_type} {{
|
|
||||||
return lookup{name}(name, c.flagSet)
|
|
||||||
}}
|
|
||||||
|
|
||||||
// Global{name} looks up the value of a global {name}Flag, returns
|
|
||||||
// {context_default} if not found
|
|
||||||
func (c *Context) Global{name}(name string) {context_type} {{
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {{
|
|
||||||
return lookup{name}(name, fs)
|
|
||||||
}}
|
|
||||||
return {context_default}
|
|
||||||
}}
|
|
||||||
|
|
||||||
func lookup{name}(name string, set *flag.FlagSet) {context_type} {{
|
|
||||||
f := set.Lookup(name)
|
|
||||||
if f != nil {{
|
|
||||||
parsed, err := {parser}
|
|
||||||
if err != nil {{
|
|
||||||
return {context_default}
|
|
||||||
}}
|
|
||||||
return {parser_cast}
|
|
||||||
}}
|
|
||||||
return {context_default}
|
|
||||||
}}
|
|
||||||
""".format(**typedef))
|
|
||||||
|
|
||||||
|
|
||||||
def _write_altsrc_flag_types(outfile, types):
|
|
||||||
_fwrite(outfile, """\
|
|
||||||
package altsrc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gopkg.in/urfave/cli.v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WARNING: This file is generated!
|
|
||||||
|
|
||||||
""")
|
|
||||||
|
|
||||||
for typedef in types:
|
|
||||||
_set_typedef_defaults(typedef)
|
|
||||||
|
|
||||||
_fwrite(outfile, """\
|
|
||||||
// {name}Flag is the flag type that wraps cli.{name}Flag to allow
|
|
||||||
// for other values to be specified
|
|
||||||
type {name}Flag struct {{
|
|
||||||
cli.{name}Flag
|
|
||||||
set *flag.FlagSet
|
|
||||||
}}
|
|
||||||
|
|
||||||
// New{name}Flag creates a new {name}Flag
|
|
||||||
func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{
|
|
||||||
return &{name}Flag{{{name}Flag: fl, set: nil}}
|
|
||||||
}}
|
|
||||||
|
|
||||||
// Apply saves the flagSet for later usage calls, then calls the
|
|
||||||
// wrapped {name}Flag.Apply
|
|
||||||
func (f *{name}Flag) Apply(set *flag.FlagSet) {{
|
|
||||||
f.set = set
|
|
||||||
f.{name}Flag.Apply(set)
|
|
||||||
}}
|
|
||||||
|
|
||||||
// ApplyWithError saves the flagSet for later usage calls, then calls the
|
|
||||||
// wrapped {name}Flag.ApplyWithError
|
|
||||||
func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{
|
|
||||||
f.set = set
|
|
||||||
return f.{name}Flag.ApplyWithError(set)
|
|
||||||
}}
|
|
||||||
""".format(**typedef))
|
|
||||||
|
|
||||||
|
|
||||||
def _fwrite(outfile, text):
|
|
||||||
print(textwrap.dedent(text), end='', file=outfile)
|
|
||||||
|
|
||||||
|
|
||||||
_WRITEFUNCS = {
|
|
||||||
'cli': _write_cli_flag_types,
|
|
||||||
'altsrc': _write_altsrc_flag_types
|
|
||||||
}
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main())
|
|
338
vendor/github.com/urfave/cli/help.go
generated
vendored
338
vendor/github.com/urfave/cli/help.go
generated
vendored
@ -1,338 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"text/tabwriter"
|
|
||||||
"text/template"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AppHelpTemplate is the text template for the Default help topic.
|
|
||||||
// cli.go uses text/template to render templates. You can
|
|
||||||
// render custom help text by setting this variable.
|
|
||||||
var AppHelpTemplate = `NAME:
|
|
||||||
{{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
|
|
||||||
|
|
||||||
VERSION:
|
|
||||||
{{.Version}}{{end}}{{end}}{{if .Description}}
|
|
||||||
|
|
||||||
DESCRIPTION:
|
|
||||||
{{.Description}}{{end}}{{if len .Authors}}
|
|
||||||
|
|
||||||
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
|
|
||||||
{{range $index, $author := .Authors}}{{if $index}}
|
|
||||||
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
|
|
||||||
|
|
||||||
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
|
|
||||||
{{.Name}}:{{end}}{{range .VisibleCommands}}
|
|
||||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
|
|
||||||
|
|
||||||
GLOBAL OPTIONS:
|
|
||||||
{{range $index, $option := .VisibleFlags}}{{if $index}}
|
|
||||||
{{end}}{{$option}}{{end}}{{end}}{{if .Copyright}}
|
|
||||||
|
|
||||||
COPYRIGHT:
|
|
||||||
{{.Copyright}}{{end}}
|
|
||||||
`
|
|
||||||
|
|
||||||
// CommandHelpTemplate is the text template for the command help topic.
|
|
||||||
// cli.go uses text/template to render templates. You can
|
|
||||||
// render custom help text by setting this variable.
|
|
||||||
var CommandHelpTemplate = `NAME:
|
|
||||||
{{.HelpName}} - {{.Usage}}
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
|
|
||||||
|
|
||||||
CATEGORY:
|
|
||||||
{{.Category}}{{end}}{{if .Description}}
|
|
||||||
|
|
||||||
DESCRIPTION:
|
|
||||||
{{.Description}}{{end}}{{if .VisibleFlags}}
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
{{range .VisibleFlags}}{{.}}
|
|
||||||
{{end}}{{end}}
|
|
||||||
`
|
|
||||||
|
|
||||||
// SubcommandHelpTemplate is the text template for the subcommand help topic.
|
|
||||||
// cli.go uses text/template to render templates. You can
|
|
||||||
// render custom help text by setting this variable.
|
|
||||||
var SubcommandHelpTemplate = `NAME:
|
|
||||||
{{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}}
|
|
||||||
|
|
||||||
USAGE:
|
|
||||||
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
|
|
||||||
|
|
||||||
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
|
|
||||||
{{.Name}}:{{end}}{{range .VisibleCommands}}
|
|
||||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
|
|
||||||
{{end}}{{if .VisibleFlags}}
|
|
||||||
OPTIONS:
|
|
||||||
{{range .VisibleFlags}}{{.}}
|
|
||||||
{{end}}{{end}}
|
|
||||||
`
|
|
||||||
|
|
||||||
var helpCommand = Command{
|
|
||||||
Name: "help",
|
|
||||||
Aliases: []string{"h"},
|
|
||||||
Usage: "Shows a list of commands or help for one command",
|
|
||||||
ArgsUsage: "[command]",
|
|
||||||
Action: func(c *Context) error {
|
|
||||||
args := c.Args()
|
|
||||||
if args.Present() {
|
|
||||||
return ShowCommandHelp(c, args.First())
|
|
||||||
}
|
|
||||||
|
|
||||||
ShowAppHelp(c)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var helpSubcommand = Command{
|
|
||||||
Name: "help",
|
|
||||||
Aliases: []string{"h"},
|
|
||||||
Usage: "Shows a list of commands or help for one command",
|
|
||||||
ArgsUsage: "[command]",
|
|
||||||
Action: func(c *Context) error {
|
|
||||||
args := c.Args()
|
|
||||||
if args.Present() {
|
|
||||||
return ShowCommandHelp(c, args.First())
|
|
||||||
}
|
|
||||||
|
|
||||||
return ShowSubcommandHelp(c)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prints help for the App or Command
|
|
||||||
type helpPrinter func(w io.Writer, templ string, data interface{})
|
|
||||||
|
|
||||||
// Prints help for the App or Command with custom template function.
|
|
||||||
type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{})
|
|
||||||
|
|
||||||
// HelpPrinter is a function that writes the help output. If not set a default
|
|
||||||
// is used. The function signature is:
|
|
||||||
// func(w io.Writer, templ string, data interface{})
|
|
||||||
var HelpPrinter helpPrinter = printHelp
|
|
||||||
|
|
||||||
// HelpPrinterCustom is same as HelpPrinter but
|
|
||||||
// takes a custom function for template function map.
|
|
||||||
var HelpPrinterCustom helpPrinterCustom = printHelpCustom
|
|
||||||
|
|
||||||
// VersionPrinter prints the version for the App
|
|
||||||
var VersionPrinter = printVersion
|
|
||||||
|
|
||||||
// ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code.
|
|
||||||
func ShowAppHelpAndExit(c *Context, exitCode int) {
|
|
||||||
ShowAppHelp(c)
|
|
||||||
os.Exit(exitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowAppHelp is an action that displays the help.
|
|
||||||
func ShowAppHelp(c *Context) (err error) {
|
|
||||||
if c.App.CustomAppHelpTemplate == "" {
|
|
||||||
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
customAppData := func() map[string]interface{} {
|
|
||||||
if c.App.ExtraInfo == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return map[string]interface{}{
|
|
||||||
"ExtraInfo": c.App.ExtraInfo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultAppComplete prints the list of subcommands as the default app completion method
|
|
||||||
func DefaultAppComplete(c *Context) {
|
|
||||||
for _, command := range c.App.Commands {
|
|
||||||
if command.Hidden {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, name := range command.Names() {
|
|
||||||
fmt.Fprintln(c.App.Writer, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowCommandHelpAndExit - exits with code after showing help
|
|
||||||
func ShowCommandHelpAndExit(c *Context, command string, code int) {
|
|
||||||
ShowCommandHelp(c, command)
|
|
||||||
os.Exit(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowCommandHelp prints help for the given command
|
|
||||||
func ShowCommandHelp(ctx *Context, command string) error {
|
|
||||||
// show the subcommand help for a command with subcommands
|
|
||||||
if command == "" {
|
|
||||||
HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range ctx.App.Commands {
|
|
||||||
if c.HasName(command) {
|
|
||||||
if c.CustomHelpTemplate != "" {
|
|
||||||
HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil)
|
|
||||||
} else {
|
|
||||||
HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctx.App.CommandNotFound == nil {
|
|
||||||
return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.App.CommandNotFound(ctx, command)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowSubcommandHelp prints help for the given subcommand
|
|
||||||
func ShowSubcommandHelp(c *Context) error {
|
|
||||||
return ShowCommandHelp(c, c.Command.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowVersion prints the version number of the App
|
|
||||||
func ShowVersion(c *Context) {
|
|
||||||
VersionPrinter(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printVersion(c *Context) {
|
|
||||||
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowCompletions prints the lists of commands within a given context
|
|
||||||
func ShowCompletions(c *Context) {
|
|
||||||
a := c.App
|
|
||||||
if a != nil && a.BashComplete != nil {
|
|
||||||
a.BashComplete(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShowCommandCompletions prints the custom completions for a given command
|
|
||||||
func ShowCommandCompletions(ctx *Context, command string) {
|
|
||||||
c := ctx.App.Command(command)
|
|
||||||
if c != nil && c.BashComplete != nil {
|
|
||||||
c.BashComplete(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) {
|
|
||||||
funcMap := template.FuncMap{
|
|
||||||
"join": strings.Join,
|
|
||||||
}
|
|
||||||
if customFunc != nil {
|
|
||||||
for key, value := range customFunc {
|
|
||||||
funcMap[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
|
|
||||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
|
||||||
err := t.Execute(w, data)
|
|
||||||
if err != nil {
|
|
||||||
// If the writer is closed, t.Execute will fail, and there's nothing
|
|
||||||
// we can do to recover.
|
|
||||||
if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
|
|
||||||
fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func printHelp(out io.Writer, templ string, data interface{}) {
|
|
||||||
printHelpCustom(out, templ, data, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkVersion(c *Context) bool {
|
|
||||||
found := false
|
|
||||||
if VersionFlag.GetName() != "" {
|
|
||||||
eachName(VersionFlag.GetName(), func(name string) {
|
|
||||||
if c.GlobalBool(name) || c.Bool(name) {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkHelp(c *Context) bool {
|
|
||||||
found := false
|
|
||||||
if HelpFlag.GetName() != "" {
|
|
||||||
eachName(HelpFlag.GetName(), func(name string) {
|
|
||||||
if c.GlobalBool(name) || c.Bool(name) {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCommandHelp(c *Context, name string) bool {
|
|
||||||
if c.Bool("h") || c.Bool("help") {
|
|
||||||
ShowCommandHelp(c, name)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkSubcommandHelp(c *Context) bool {
|
|
||||||
if c.Bool("h") || c.Bool("help") {
|
|
||||||
ShowSubcommandHelp(c)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) {
|
|
||||||
if !a.EnableBashCompletion {
|
|
||||||
return false, arguments
|
|
||||||
}
|
|
||||||
|
|
||||||
pos := len(arguments) - 1
|
|
||||||
lastArg := arguments[pos]
|
|
||||||
|
|
||||||
if lastArg != "--"+BashCompletionFlag.GetName() {
|
|
||||||
return false, arguments
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, arguments[:pos]
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCompletions(c *Context) bool {
|
|
||||||
if !c.shellComplete {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if args := c.Args(); args.Present() {
|
|
||||||
name := args.First()
|
|
||||||
if cmd := c.App.Command(name); cmd != nil {
|
|
||||||
// let the command handle the completion
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShowCompletions(c)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCommandCompletions(c *Context, name string) bool {
|
|
||||||
if !c.shellComplete {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
ShowCommandCompletions(c, name)
|
|
||||||
return true
|
|
||||||
}
|
|
122
vendor/github.com/urfave/cli/runtests
generated
vendored
122
vendor/github.com/urfave/cli/runtests
generated
vendored
@ -1,122 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
from subprocess import check_call, check_output
|
|
||||||
|
|
||||||
|
|
||||||
PACKAGE_NAME = os.environ.get(
|
|
||||||
'CLI_PACKAGE_NAME', 'github.com/urfave/cli'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main(sysargs=sys.argv[:]):
|
|
||||||
targets = {
|
|
||||||
'vet': _vet,
|
|
||||||
'test': _test,
|
|
||||||
'gfmrun': _gfmrun,
|
|
||||||
'toc': _toc,
|
|
||||||
'gen': _gen,
|
|
||||||
}
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument(
|
|
||||||
'target', nargs='?', choices=tuple(targets.keys()), default='test'
|
|
||||||
)
|
|
||||||
args = parser.parse_args(sysargs[1:])
|
|
||||||
|
|
||||||
targets[args.target]()
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def _test():
|
|
||||||
if check_output('go version'.split()).split()[2] < 'go1.2':
|
|
||||||
_run('go test -v .')
|
|
||||||
return
|
|
||||||
|
|
||||||
coverprofiles = []
|
|
||||||
for subpackage in ['', 'altsrc']:
|
|
||||||
coverprofile = 'cli.coverprofile'
|
|
||||||
if subpackage != '':
|
|
||||||
coverprofile = '{}.coverprofile'.format(subpackage)
|
|
||||||
|
|
||||||
coverprofiles.append(coverprofile)
|
|
||||||
|
|
||||||
_run('go test -v'.split() + [
|
|
||||||
'-coverprofile={}'.format(coverprofile),
|
|
||||||
('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/')
|
|
||||||
])
|
|
||||||
|
|
||||||
combined_name = _combine_coverprofiles(coverprofiles)
|
|
||||||
_run('go tool cover -func={}'.format(combined_name))
|
|
||||||
os.remove(combined_name)
|
|
||||||
|
|
||||||
|
|
||||||
def _gfmrun():
|
|
||||||
go_version = check_output('go version'.split()).split()[2]
|
|
||||||
if go_version < 'go1.3':
|
|
||||||
print('runtests: skip on {}'.format(go_version), file=sys.stderr)
|
|
||||||
return
|
|
||||||
_run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md'])
|
|
||||||
|
|
||||||
|
|
||||||
def _vet():
|
|
||||||
_run('go vet ./...')
|
|
||||||
|
|
||||||
|
|
||||||
def _toc():
|
|
||||||
_run('node_modules/.bin/markdown-toc -i README.md')
|
|
||||||
_run('git diff --exit-code')
|
|
||||||
|
|
||||||
|
|
||||||
def _gen():
|
|
||||||
go_version = check_output('go version'.split()).split()[2]
|
|
||||||
if go_version < 'go1.5':
|
|
||||||
print('runtests: skip on {}'.format(go_version), file=sys.stderr)
|
|
||||||
return
|
|
||||||
|
|
||||||
_run('go generate ./...')
|
|
||||||
_run('git diff --exit-code')
|
|
||||||
|
|
||||||
|
|
||||||
def _run(command):
|
|
||||||
if hasattr(command, 'split'):
|
|
||||||
command = command.split()
|
|
||||||
print('runtests: {}'.format(' '.join(command)), file=sys.stderr)
|
|
||||||
check_call(command)
|
|
||||||
|
|
||||||
|
|
||||||
def _gfmrun_count():
|
|
||||||
with open('README.md') as infile:
|
|
||||||
lines = infile.read().splitlines()
|
|
||||||
return len(filter(_is_go_runnable, lines))
|
|
||||||
|
|
||||||
|
|
||||||
def _is_go_runnable(line):
|
|
||||||
return line.startswith('package main')
|
|
||||||
|
|
||||||
|
|
||||||
def _combine_coverprofiles(coverprofiles):
|
|
||||||
combined = tempfile.NamedTemporaryFile(
|
|
||||||
suffix='.coverprofile', delete=False
|
|
||||||
)
|
|
||||||
combined.write('mode: set\n')
|
|
||||||
|
|
||||||
for coverprofile in coverprofiles:
|
|
||||||
with open(coverprofile, 'r') as infile:
|
|
||||||
for line in infile.readlines():
|
|
||||||
if not line.startswith('mode: '):
|
|
||||||
combined.write(line)
|
|
||||||
|
|
||||||
combined.flush()
|
|
||||||
name = combined.name
|
|
||||||
combined.close()
|
|
||||||
return name
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main())
|
|
21
vendor/gopkg.in/telegram-bot-api.v4/LICENSE.txt
generated
vendored
21
vendor/gopkg.in/telegram-bot-api.v4/LICENSE.txt
generated
vendored
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Syfaro
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
112
vendor/gopkg.in/telegram-bot-api.v4/README.md
generated
vendored
112
vendor/gopkg.in/telegram-bot-api.v4/README.md
generated
vendored
@ -1,112 +0,0 @@
|
|||||||
# Golang bindings for the Telegram Bot API
|
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
|
|
||||||
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
|
||||||
|
|
||||||
All methods have been added, and all features should be available.
|
|
||||||
If you want a feature that hasn't been added yet or something is broken,
|
|
||||||
open an issue and I'll see what I can do.
|
|
||||||
|
|
||||||
All methods are fairly self explanatory, and reading the godoc page should
|
|
||||||
explain everything. If something isn't clear, open an issue or submit
|
|
||||||
a pull request.
|
|
||||||
|
|
||||||
The scope of this project is just to provide a wrapper around the API
|
|
||||||
without any additional features. There are other projects for creating
|
|
||||||
something with plugins and command handlers without having to design
|
|
||||||
all that yourself.
|
|
||||||
|
|
||||||
Use `github.com/go-telegram-bot-api/telegram-bot-api` for the latest
|
|
||||||
version, or use `gopkg.in/telegram-bot-api.v4` for the stable build.
|
|
||||||
|
|
||||||
Join [the development group](https://telegram.me/go_telegram_bot_api) if
|
|
||||||
you want to ask questions or discuss development.
|
|
||||||
|
|
||||||
## Example
|
|
||||||
|
|
||||||
This is a very simple bot that just displays any gotten updates,
|
|
||||||
then replies it to that chat.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"gopkg.in/telegram-bot-api.v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken")
|
|
||||||
if err != nil {
|
|
||||||
log.Panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.Debug = true
|
|
||||||
|
|
||||||
log.Printf("Authorized on account %s", bot.Self.UserName)
|
|
||||||
|
|
||||||
u := tgbotapi.NewUpdate(0)
|
|
||||||
u.Timeout = 60
|
|
||||||
|
|
||||||
updates, err := bot.GetUpdatesChan(u)
|
|
||||||
|
|
||||||
for update := range updates {
|
|
||||||
if update.Message == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
|
|
||||||
|
|
||||||
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text)
|
|
||||||
msg.ReplyToMessageID = update.Message.MessageID
|
|
||||||
|
|
||||||
bot.Send(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you need to use webhooks (if you wish to run on Google App Engine),
|
|
||||||
you may use a slightly different method.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gopkg.in/telegram-bot-api.v4"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.Debug = true
|
|
||||||
|
|
||||||
log.Printf("Authorized on account %s", bot.Self.UserName)
|
|
||||||
|
|
||||||
_, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
updates := bot.ListenForWebhook("/" + bot.Token)
|
|
||||||
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil)
|
|
||||||
|
|
||||||
for update := range updates {
|
|
||||||
log.Printf("%+v\n", update)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you need, you may generate a self signed certficate, as this requires
|
|
||||||
HTTPS / TLS. The above example tells Telegram that this is your
|
|
||||||
certificate and that it should be trusted, even though it is not
|
|
||||||
properly signed.
|
|
||||||
|
|
||||||
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3560 -subj "//O=Org\CN=Test" -nodes
|
|
||||||
|
|
||||||
Now that [Let's Encrypt](https://letsencrypt.org) has entered public beta,
|
|
||||||
you may wish to generate your free TLS certificate there.
|
|
900
vendor/gopkg.in/telegram-bot-api.v4/bot.go
generated
vendored
900
vendor/gopkg.in/telegram-bot-api.v4/bot.go
generated
vendored
@ -1,900 +0,0 @@
|
|||||||
// Package tgbotapi has functions and types used for interacting with
|
|
||||||
// the Telegram Bot API.
|
|
||||||
package tgbotapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/technoweenie/multipartstreamer"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BotAPI allows you to interact with the Telegram Bot API.
|
|
||||||
type BotAPI struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
Debug bool `json:"debug"`
|
|
||||||
Buffer int `json:"buffer"`
|
|
||||||
|
|
||||||
Self User `json:"-"`
|
|
||||||
Client *http.Client `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBotAPI creates a new BotAPI instance.
|
|
||||||
//
|
|
||||||
// It requires a token, provided by @BotFather on Telegram.
|
|
||||||
func NewBotAPI(token string) (*BotAPI, error) {
|
|
||||||
return NewBotAPIWithClient(token, &http.Client{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBotAPIWithClient creates a new BotAPI instance
|
|
||||||
// and allows you to pass a http.Client.
|
|
||||||
//
|
|
||||||
// It requires a token, provided by @BotFather on Telegram.
|
|
||||||
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
|
||||||
bot := &BotAPI{
|
|
||||||
Token: token,
|
|
||||||
Client: client,
|
|
||||||
Buffer: 100,
|
|
||||||
}
|
|
||||||
|
|
||||||
self, err := bot.GetMe()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.Self = self
|
|
||||||
|
|
||||||
return bot, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRequest makes a request to a specific endpoint with our token.
|
|
||||||
func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) {
|
|
||||||
method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint)
|
|
||||||
|
|
||||||
resp, err := bot.Client.PostForm(method, params)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
var apiResp APIResponse
|
|
||||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
|
||||||
if err != nil {
|
|
||||||
return apiResp, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if bot.Debug {
|
|
||||||
log.Printf("%s resp: %s", endpoint, bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !apiResp.Ok {
|
|
||||||
return apiResp, errors.New(apiResp.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiResp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// decodeAPIResponse decode response and return slice of bytes if debug enabled.
|
|
||||||
// If debug disabled, just decode http.Response.Body stream to APIResponse struct
|
|
||||||
// for efficient memory usage
|
|
||||||
func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) (_ []byte, err error) {
|
|
||||||
if !bot.Debug {
|
|
||||||
dec := json.NewDecoder(responseBody)
|
|
||||||
err = dec.Decode(resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// if debug, read reponse body
|
|
||||||
data, err := ioutil.ReadAll(responseBody)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, resp)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeMessageRequest makes a request to a method that returns a Message.
|
|
||||||
func (bot *BotAPI) makeMessageRequest(endpoint string, params url.Values) (Message, error) {
|
|
||||||
resp, err := bot.MakeRequest(endpoint, params)
|
|
||||||
if err != nil {
|
|
||||||
return Message{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var message Message
|
|
||||||
json.Unmarshal(resp.Result, &message)
|
|
||||||
|
|
||||||
bot.debugLog(endpoint, params, message)
|
|
||||||
|
|
||||||
return message, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadFile makes a request to the API with a file.
|
|
||||||
//
|
|
||||||
// Requires the parameter to hold the file not be in the params.
|
|
||||||
// File should be a string to a file path, a FileBytes struct,
|
|
||||||
// a FileReader struct, or a url.URL.
|
|
||||||
//
|
|
||||||
// Note that if your FileReader has a size set to -1, it will read
|
|
||||||
// the file into memory to calculate a size.
|
|
||||||
func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldname string, file interface{}) (APIResponse, error) {
|
|
||||||
ms := multipartstreamer.New()
|
|
||||||
|
|
||||||
switch f := file.(type) {
|
|
||||||
case string:
|
|
||||||
ms.WriteFields(params)
|
|
||||||
|
|
||||||
fileHandle, err := os.Open(f)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
defer fileHandle.Close()
|
|
||||||
|
|
||||||
fi, err := os.Stat(f)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.WriteReader(fieldname, fileHandle.Name(), fi.Size(), fileHandle)
|
|
||||||
case FileBytes:
|
|
||||||
ms.WriteFields(params)
|
|
||||||
|
|
||||||
buf := bytes.NewBuffer(f.Bytes)
|
|
||||||
ms.WriteReader(fieldname, f.Name, int64(len(f.Bytes)), buf)
|
|
||||||
case FileReader:
|
|
||||||
ms.WriteFields(params)
|
|
||||||
|
|
||||||
if f.Size != -1 {
|
|
||||||
ms.WriteReader(fieldname, f.Name, f.Size, f.Reader)
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(f.Reader)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := bytes.NewBuffer(data)
|
|
||||||
|
|
||||||
ms.WriteReader(fieldname, f.Name, int64(len(data)), buf)
|
|
||||||
case url.URL:
|
|
||||||
params[fieldname] = f.String()
|
|
||||||
|
|
||||||
ms.WriteFields(params)
|
|
||||||
default:
|
|
||||||
return APIResponse{}, errors.New(ErrBadFileType)
|
|
||||||
}
|
|
||||||
|
|
||||||
method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", method, nil)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.SetupRequest(req)
|
|
||||||
|
|
||||||
res, err := bot.Client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
bytes, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if bot.Debug {
|
|
||||||
log.Println(string(bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
var apiResp APIResponse
|
|
||||||
|
|
||||||
err = json.Unmarshal(bytes, &apiResp)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !apiResp.Ok {
|
|
||||||
return APIResponse{}, errors.New(apiResp.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
return apiResp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFileDirectURL returns direct URL to file
|
|
||||||
//
|
|
||||||
// It requires the FileID.
|
|
||||||
func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) {
|
|
||||||
file, err := bot.GetFile(FileConfig{fileID})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return file.Link(bot.Token), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMe fetches the currently authenticated bot.
|
|
||||||
//
|
|
||||||
// This method is called upon creation to validate the token,
|
|
||||||
// and so you may get this data from BotAPI.Self without the need for
|
|
||||||
// another request.
|
|
||||||
func (bot *BotAPI) GetMe() (User, error) {
|
|
||||||
resp, err := bot.MakeRequest("getMe", nil)
|
|
||||||
if err != nil {
|
|
||||||
return User{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var user User
|
|
||||||
json.Unmarshal(resp.Result, &user)
|
|
||||||
|
|
||||||
bot.debugLog("getMe", nil, user)
|
|
||||||
|
|
||||||
return user, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsMessageToMe returns true if message directed to this bot.
|
|
||||||
//
|
|
||||||
// It requires the Message.
|
|
||||||
func (bot *BotAPI) IsMessageToMe(message Message) bool {
|
|
||||||
return strings.Contains(message.Text, "@"+bot.Self.UserName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send will send a Chattable item to Telegram.
|
|
||||||
//
|
|
||||||
// It requires the Chattable to send.
|
|
||||||
func (bot *BotAPI) Send(c Chattable) (Message, error) {
|
|
||||||
switch c.(type) {
|
|
||||||
case Fileable:
|
|
||||||
return bot.sendFile(c.(Fileable))
|
|
||||||
default:
|
|
||||||
return bot.sendChattable(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// debugLog checks if the bot is currently running in debug mode, and if
|
|
||||||
// so will display information about the request and response in the
|
|
||||||
// debug log.
|
|
||||||
func (bot *BotAPI) debugLog(context string, v url.Values, message interface{}) {
|
|
||||||
if bot.Debug {
|
|
||||||
log.Printf("%s req : %+v\n", context, v)
|
|
||||||
log.Printf("%s resp: %+v\n", context, message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendExisting will send a Message with an existing file to Telegram.
|
|
||||||
func (bot *BotAPI) sendExisting(method string, config Fileable) (Message, error) {
|
|
||||||
v, err := config.values()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Message{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
message, err := bot.makeMessageRequest(method, v)
|
|
||||||
if err != nil {
|
|
||||||
return Message{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return message, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// uploadAndSend will send a Message with a new file to Telegram.
|
|
||||||
func (bot *BotAPI) uploadAndSend(method string, config Fileable) (Message, error) {
|
|
||||||
params, err := config.params()
|
|
||||||
if err != nil {
|
|
||||||
return Message{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
file := config.getFile()
|
|
||||||
|
|
||||||
resp, err := bot.UploadFile(method, params, config.name(), file)
|
|
||||||
if err != nil {
|
|
||||||
return Message{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var message Message
|
|
||||||
json.Unmarshal(resp.Result, &message)
|
|
||||||
|
|
||||||
bot.debugLog(method, nil, message)
|
|
||||||
|
|
||||||
return message, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendFile determines if the file is using an existing file or uploading
|
|
||||||
// a new file, then sends it as needed.
|
|
||||||
func (bot *BotAPI) sendFile(config Fileable) (Message, error) {
|
|
||||||
if config.useExistingFile() {
|
|
||||||
return bot.sendExisting(config.method(), config)
|
|
||||||
}
|
|
||||||
|
|
||||||
return bot.uploadAndSend(config.method(), config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendChattable sends a Chattable.
|
|
||||||
func (bot *BotAPI) sendChattable(config Chattable) (Message, error) {
|
|
||||||
v, err := config.values()
|
|
||||||
if err != nil {
|
|
||||||
return Message{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
message, err := bot.makeMessageRequest(config.method(), v)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return Message{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return message, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserProfilePhotos gets a user's profile photos.
|
|
||||||
//
|
|
||||||
// It requires UserID.
|
|
||||||
// Offset and Limit are optional.
|
|
||||||
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
|
||||||
if config.Offset != 0 {
|
|
||||||
v.Add("offset", strconv.Itoa(config.Offset))
|
|
||||||
}
|
|
||||||
if config.Limit != 0 {
|
|
||||||
v.Add("limit", strconv.Itoa(config.Limit))
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("getUserProfilePhotos", v)
|
|
||||||
if err != nil {
|
|
||||||
return UserProfilePhotos{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var profilePhotos UserProfilePhotos
|
|
||||||
json.Unmarshal(resp.Result, &profilePhotos)
|
|
||||||
|
|
||||||
bot.debugLog("GetUserProfilePhoto", v, profilePhotos)
|
|
||||||
|
|
||||||
return profilePhotos, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFile returns a File which can download a file from Telegram.
|
|
||||||
//
|
|
||||||
// Requires FileID.
|
|
||||||
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
v.Add("file_id", config.FileID)
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("getFile", v)
|
|
||||||
if err != nil {
|
|
||||||
return File{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var file File
|
|
||||||
json.Unmarshal(resp.Result, &file)
|
|
||||||
|
|
||||||
bot.debugLog("GetFile", v, file)
|
|
||||||
|
|
||||||
return file, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpdates fetches updates.
|
|
||||||
// If a WebHook is set, this will not return any data!
|
|
||||||
//
|
|
||||||
// Offset, Limit, and Timeout are optional.
|
|
||||||
// To avoid stale items, set Offset to one higher than the previous item.
|
|
||||||
// Set Timeout to a large number to reduce requests so you can get updates
|
|
||||||
// instantly instead of having to wait between requests.
|
|
||||||
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
if config.Offset != 0 {
|
|
||||||
v.Add("offset", strconv.Itoa(config.Offset))
|
|
||||||
}
|
|
||||||
if config.Limit > 0 {
|
|
||||||
v.Add("limit", strconv.Itoa(config.Limit))
|
|
||||||
}
|
|
||||||
if config.Timeout > 0 {
|
|
||||||
v.Add("timeout", strconv.Itoa(config.Timeout))
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("getUpdates", v)
|
|
||||||
if err != nil {
|
|
||||||
return []Update{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var updates []Update
|
|
||||||
json.Unmarshal(resp.Result, &updates)
|
|
||||||
|
|
||||||
bot.debugLog("getUpdates", v, updates)
|
|
||||||
|
|
||||||
return updates, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveWebhook unsets the webhook.
|
|
||||||
func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
|
|
||||||
return bot.MakeRequest("setWebhook", url.Values{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetWebhook sets a webhook.
|
|
||||||
//
|
|
||||||
// If this is set, GetUpdates will not get any data!
|
|
||||||
//
|
|
||||||
// If you do not have a legitimate TLS certificate, you need to include
|
|
||||||
// your self signed certificate with the config.
|
|
||||||
func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) {
|
|
||||||
|
|
||||||
if config.Certificate == nil {
|
|
||||||
v := url.Values{}
|
|
||||||
v.Add("url", config.URL.String())
|
|
||||||
if config.MaxConnections != 0 {
|
|
||||||
v.Add("max_connections", strconv.Itoa(config.MaxConnections))
|
|
||||||
}
|
|
||||||
|
|
||||||
return bot.MakeRequest("setWebhook", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
params := make(map[string]string)
|
|
||||||
params["url"] = config.URL.String()
|
|
||||||
if config.MaxConnections != 0 {
|
|
||||||
params["max_connections"] = strconv.Itoa(config.MaxConnections)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.UploadFile("setWebhook", params, "certificate", config.Certificate)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWebhookInfo allows you to fetch information about a webhook and if
|
|
||||||
// one currently is set, along with pending update count and error messages.
|
|
||||||
func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
|
|
||||||
resp, err := bot.MakeRequest("getWebhookInfo", url.Values{})
|
|
||||||
if err != nil {
|
|
||||||
return WebhookInfo{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var info WebhookInfo
|
|
||||||
err = json.Unmarshal(resp.Result, &info)
|
|
||||||
|
|
||||||
return info, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpdatesChan starts and returns a channel for getting updates.
|
|
||||||
func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
|
|
||||||
ch := make(chan Update, bot.Buffer)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
updates, err := bot.GetUpdates(config)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
log.Println("Failed to get updates, retrying in 3 seconds...")
|
|
||||||
time.Sleep(time.Second * 3)
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, update := range updates {
|
|
||||||
if update.UpdateID >= config.Offset {
|
|
||||||
config.Offset = update.UpdateID + 1
|
|
||||||
ch <- update
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return ch, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenForWebhook registers a http handler for a webhook.
|
|
||||||
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
|
||||||
ch := make(chan Update, bot.Buffer)
|
|
||||||
|
|
||||||
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
bytes, _ := ioutil.ReadAll(r.Body)
|
|
||||||
|
|
||||||
var update Update
|
|
||||||
json.Unmarshal(bytes, &update)
|
|
||||||
|
|
||||||
ch <- update
|
|
||||||
})
|
|
||||||
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnswerInlineQuery sends a response to an inline query.
|
|
||||||
//
|
|
||||||
// Note that you must respond to an inline query within 30 seconds.
|
|
||||||
func (bot *BotAPI) AnswerInlineQuery(config InlineConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
v.Add("inline_query_id", config.InlineQueryID)
|
|
||||||
v.Add("cache_time", strconv.Itoa(config.CacheTime))
|
|
||||||
v.Add("is_personal", strconv.FormatBool(config.IsPersonal))
|
|
||||||
v.Add("next_offset", config.NextOffset)
|
|
||||||
data, err := json.Marshal(config.Results)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
v.Add("results", string(data))
|
|
||||||
v.Add("switch_pm_text", config.SwitchPMText)
|
|
||||||
v.Add("switch_pm_parameter", config.SwitchPMParameter)
|
|
||||||
|
|
||||||
bot.debugLog("answerInlineQuery", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("answerInlineQuery", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnswerCallbackQuery sends a response to an inline query callback.
|
|
||||||
func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
v.Add("callback_query_id", config.CallbackQueryID)
|
|
||||||
if config.Text != "" {
|
|
||||||
v.Add("text", config.Text)
|
|
||||||
}
|
|
||||||
v.Add("show_alert", strconv.FormatBool(config.ShowAlert))
|
|
||||||
if config.URL != "" {
|
|
||||||
v.Add("url", config.URL)
|
|
||||||
}
|
|
||||||
v.Add("cache_time", strconv.Itoa(config.CacheTime))
|
|
||||||
|
|
||||||
bot.debugLog("answerCallbackQuery", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("answerCallbackQuery", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// KickChatMember kicks a user from a chat. Note that this only will work
|
|
||||||
// in supergroups, and requires the bot to be an admin. Also note they
|
|
||||||
// will be unable to rejoin until they are unbanned.
|
|
||||||
func (bot *BotAPI) KickChatMember(config KickChatMemberConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
}
|
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
|
||||||
|
|
||||||
if config.UntilDate != 0 {
|
|
||||||
v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog("kickChatMember", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("kickChatMember", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LeaveChat makes the bot leave the chat.
|
|
||||||
func (bot *BotAPI) LeaveChat(config ChatConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog("leaveChat", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("leaveChat", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChat gets information about a chat.
|
|
||||||
func (bot *BotAPI) GetChat(config ChatConfig) (Chat, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("getChat", v)
|
|
||||||
if err != nil {
|
|
||||||
return Chat{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var chat Chat
|
|
||||||
err = json.Unmarshal(resp.Result, &chat)
|
|
||||||
|
|
||||||
bot.debugLog("getChat", v, chat)
|
|
||||||
|
|
||||||
return chat, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatAdministrators gets a list of administrators in the chat.
|
|
||||||
//
|
|
||||||
// If none have been appointed, only the creator will be returned.
|
|
||||||
// Bots are not shown, even if they are an administrator.
|
|
||||||
func (bot *BotAPI) GetChatAdministrators(config ChatConfig) ([]ChatMember, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("getChatAdministrators", v)
|
|
||||||
if err != nil {
|
|
||||||
return []ChatMember{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var members []ChatMember
|
|
||||||
err = json.Unmarshal(resp.Result, &members)
|
|
||||||
|
|
||||||
bot.debugLog("getChatAdministrators", v, members)
|
|
||||||
|
|
||||||
return members, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatMembersCount gets the number of users in a chat.
|
|
||||||
func (bot *BotAPI) GetChatMembersCount(config ChatConfig) (int, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("getChatMembersCount", v)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var count int
|
|
||||||
err = json.Unmarshal(resp.Result, &count)
|
|
||||||
|
|
||||||
bot.debugLog("getChatMembersCount", v, count)
|
|
||||||
|
|
||||||
return count, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatMember gets a specific chat member.
|
|
||||||
func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
}
|
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("getChatMember", v)
|
|
||||||
if err != nil {
|
|
||||||
return ChatMember{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var member ChatMember
|
|
||||||
err = json.Unmarshal(resp.Result, &member)
|
|
||||||
|
|
||||||
bot.debugLog("getChatMember", v, member)
|
|
||||||
|
|
||||||
return member, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnbanChatMember unbans a user from a chat. Note that this only will work
|
|
||||||
// in supergroups and channels, and requires the bot to be an admin.
|
|
||||||
func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername != "" {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
} else if config.ChannelUsername != "" {
|
|
||||||
v.Add("chat_id", config.ChannelUsername)
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
}
|
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
|
||||||
|
|
||||||
bot.debugLog("unbanChatMember", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("unbanChatMember", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RestrictChatMember to restrict a user in a supergroup. The bot must be an
|
|
||||||
//administrator in the supergroup for this to work and must have the
|
|
||||||
//appropriate admin rights. Pass True for all boolean parameters to lift
|
|
||||||
//restrictions from a user. Returns True on success.
|
|
||||||
func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername != "" {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
} else if config.ChannelUsername != "" {
|
|
||||||
v.Add("chat_id", config.ChannelUsername)
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
}
|
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
|
||||||
|
|
||||||
if &config.CanSendMessages != nil {
|
|
||||||
v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages))
|
|
||||||
}
|
|
||||||
if &config.CanSendMediaMessages != nil {
|
|
||||||
v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages))
|
|
||||||
}
|
|
||||||
if &config.CanSendOtherMessages != nil {
|
|
||||||
v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages))
|
|
||||||
}
|
|
||||||
if &config.CanAddWebPagePreviews != nil {
|
|
||||||
v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews))
|
|
||||||
}
|
|
||||||
if config.UntilDate != 0 {
|
|
||||||
v.Add("until_date", strconv.FormatInt(config.UntilDate, 10))
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog("restrictChatMember", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("restrictChatMember", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PromoteChatMember add admin rights to user
|
|
||||||
func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername != "" {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
} else if config.ChannelUsername != "" {
|
|
||||||
v.Add("chat_id", config.ChannelUsername)
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
}
|
|
||||||
v.Add("user_id", strconv.Itoa(config.UserID))
|
|
||||||
|
|
||||||
if &config.CanChangeInfo != nil {
|
|
||||||
v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo))
|
|
||||||
}
|
|
||||||
if &config.CanPostMessages != nil {
|
|
||||||
v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages))
|
|
||||||
}
|
|
||||||
if &config.CanEditMessages != nil {
|
|
||||||
v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages))
|
|
||||||
}
|
|
||||||
if &config.CanDeleteMessages != nil {
|
|
||||||
v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages))
|
|
||||||
}
|
|
||||||
if &config.CanInviteUsers != nil {
|
|
||||||
v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers))
|
|
||||||
}
|
|
||||||
if &config.CanRestrictMembers != nil {
|
|
||||||
v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers))
|
|
||||||
}
|
|
||||||
if &config.CanPinMessages != nil {
|
|
||||||
v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages))
|
|
||||||
}
|
|
||||||
if &config.CanPromoteMembers != nil {
|
|
||||||
v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers))
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog("promoteChatMember", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("promoteChatMember", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGameHighScores allows you to get the high scores for a game.
|
|
||||||
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
|
||||||
v, _ := config.values()
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), v)
|
|
||||||
if err != nil {
|
|
||||||
return []GameHighScore{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var highScores []GameHighScore
|
|
||||||
err = json.Unmarshal(resp.Result, &highScores)
|
|
||||||
|
|
||||||
return highScores, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnswerShippingQuery allows you to reply to Update with shipping_query parameter.
|
|
||||||
func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
v.Add("shipping_query_id", config.ShippingQueryID)
|
|
||||||
v.Add("ok", strconv.FormatBool(config.OK))
|
|
||||||
if config.OK == true {
|
|
||||||
data, err := json.Marshal(config.ShippingOptions)
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
v.Add("shipping_options", string(data))
|
|
||||||
} else {
|
|
||||||
v.Add("error_message", config.ErrorMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog("answerShippingQuery", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("answerShippingQuery", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query.
|
|
||||||
func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
|
|
||||||
v.Add("ok", strconv.FormatBool(config.OK))
|
|
||||||
if config.OK != true {
|
|
||||||
v.Add("error", config.ErrorMessage)
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog("answerPreCheckoutQuery", v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest("answerPreCheckoutQuery", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteMessage deletes a message in a chat
|
|
||||||
func (bot *BotAPI) DeleteMessage(config DeleteMessageConfig) (APIResponse, error) {
|
|
||||||
v, err := config.values()
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog(config.method(), v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest(config.method(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInviteLink get InviteLink for a chat
|
|
||||||
func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
|
|
||||||
if config.SuperGroupUsername == "" {
|
|
||||||
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
|
|
||||||
} else {
|
|
||||||
v.Add("chat_id", config.SuperGroupUsername)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest("exportChatInviteLink", v)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var inviteLink string
|
|
||||||
err = json.Unmarshal(resp.Result, &inviteLink)
|
|
||||||
|
|
||||||
return inviteLink, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// PinChatMessage pin message in supergroup
|
|
||||||
func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) {
|
|
||||||
v, err := config.values()
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog(config.method(), v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest(config.method(), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnpinChatMessage unpin message in supergroup
|
|
||||||
func (bot *BotAPI) UnpinChatMessage(config UnpinChatMessageConfig) (APIResponse, error) {
|
|
||||||
v, err := config.values()
|
|
||||||
if err != nil {
|
|
||||||
return APIResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.debugLog(config.method(), v, nil)
|
|
||||||
|
|
||||||
return bot.MakeRequest(config.method(), v)
|
|
||||||
}
|
|
1075
vendor/gopkg.in/telegram-bot-api.v4/configs.go
generated
vendored
1075
vendor/gopkg.in/telegram-bot-api.v4/configs.go
generated
vendored
File diff suppressed because it is too large
Load Diff
655
vendor/gopkg.in/telegram-bot-api.v4/helpers.go
generated
vendored
655
vendor/gopkg.in/telegram-bot-api.v4/helpers.go
generated
vendored
@ -1,655 +0,0 @@
|
|||||||
package tgbotapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewMessage creates a new Message.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, text is the message text.
|
|
||||||
func NewMessage(chatID int64, text string) MessageConfig {
|
|
||||||
return MessageConfig{
|
|
||||||
BaseChat: BaseChat{
|
|
||||||
ChatID: chatID,
|
|
||||||
ReplyToMessageID: 0,
|
|
||||||
},
|
|
||||||
Text: text,
|
|
||||||
DisableWebPagePreview: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMessageToChannel creates a new Message that is sent to a channel
|
|
||||||
// by username.
|
|
||||||
//
|
|
||||||
// username is the username of the channel, text is the message text.
|
|
||||||
func NewMessageToChannel(username string, text string) MessageConfig {
|
|
||||||
return MessageConfig{
|
|
||||||
BaseChat: BaseChat{
|
|
||||||
ChannelUsername: username,
|
|
||||||
},
|
|
||||||
Text: text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewForward creates a new forward.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fromChatID is the source chat,
|
|
||||||
// and messageID is the ID of the original message.
|
|
||||||
func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
|
|
||||||
return ForwardConfig{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FromChatID: fromChatID,
|
|
||||||
MessageID: messageID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPhotoUpload creates a new photo uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
//
|
|
||||||
// Note that you must send animated GIFs as a document.
|
|
||||||
func NewPhotoUpload(chatID int64, file interface{}) PhotoConfig {
|
|
||||||
return PhotoConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
File: file,
|
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPhotoShare shares an existing photo.
|
|
||||||
// You may use this to reshare an existing photo without reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the file
|
|
||||||
// already uploaded.
|
|
||||||
func NewPhotoShare(chatID int64, fileID string) PhotoConfig {
|
|
||||||
return PhotoConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAudioUpload creates a new audio uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewAudioUpload(chatID int64, file interface{}) AudioConfig {
|
|
||||||
return AudioConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
File: file,
|
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAudioShare shares an existing audio file.
|
|
||||||
// You may use this to reshare an existing audio file without
|
|
||||||
// reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the audio
|
|
||||||
// already uploaded.
|
|
||||||
func NewAudioShare(chatID int64, fileID string) AudioConfig {
|
|
||||||
return AudioConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDocumentUpload creates a new document uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewDocumentUpload(chatID int64, file interface{}) DocumentConfig {
|
|
||||||
return DocumentConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
File: file,
|
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDocumentShare shares an existing document.
|
|
||||||
// You may use this to reshare an existing document without
|
|
||||||
// reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the document
|
|
||||||
// already uploaded.
|
|
||||||
func NewDocumentShare(chatID int64, fileID string) DocumentConfig {
|
|
||||||
return DocumentConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStickerUpload creates a new sticker uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewStickerUpload(chatID int64, file interface{}) StickerConfig {
|
|
||||||
return StickerConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
File: file,
|
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewStickerShare shares an existing sticker.
|
|
||||||
// You may use this to reshare an existing sticker without
|
|
||||||
// reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the sticker
|
|
||||||
// already uploaded.
|
|
||||||
func NewStickerShare(chatID int64, fileID string) StickerConfig {
|
|
||||||
return StickerConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVideoUpload creates a new video uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewVideoUpload(chatID int64, file interface{}) VideoConfig {
|
|
||||||
return VideoConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
File: file,
|
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVideoShare shares an existing video.
|
|
||||||
// You may use this to reshare an existing video without reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the video
|
|
||||||
// already uploaded.
|
|
||||||
func NewVideoShare(chatID int64, fileID string) VideoConfig {
|
|
||||||
return VideoConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVideoNoteUpload creates a new video note uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig {
|
|
||||||
return VideoNoteConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
File: file,
|
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
Length: length,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVideoNoteShare shares an existing video.
|
|
||||||
// You may use this to reshare an existing video without reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the video
|
|
||||||
// already uploaded.
|
|
||||||
func NewVideoNoteShare(chatID int64, length int, fileID string) VideoNoteConfig {
|
|
||||||
return VideoNoteConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
Length: length,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVoiceUpload creates a new voice uploader.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewVoiceUpload(chatID int64, file interface{}) VoiceConfig {
|
|
||||||
return VoiceConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
File: file,
|
|
||||||
UseExisting: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVoiceShare shares an existing voice.
|
|
||||||
// You may use this to reshare an existing voice without reuploading it.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, fileID is the ID of the video
|
|
||||||
// already uploaded.
|
|
||||||
func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
|
|
||||||
return VoiceConfig{
|
|
||||||
BaseFile: BaseFile{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
FileID: fileID,
|
|
||||||
UseExisting: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContact allows you to send a shared contact.
|
|
||||||
func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig {
|
|
||||||
return ContactConfig{
|
|
||||||
BaseChat: BaseChat{
|
|
||||||
ChatID: chatID,
|
|
||||||
},
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
FirstName: firstName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewLocation shares your location.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, latitude and longitude are coordinates.
|
|
||||||
func NewLocation(chatID int64, latitude float64, longitude float64) LocationConfig {
|
|
||||||
return LocationConfig{
|
|
||||||
BaseChat: BaseChat{
|
|
||||||
ChatID: chatID,
|
|
||||||
},
|
|
||||||
Latitude: latitude,
|
|
||||||
Longitude: longitude,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVenue allows you to send a venue and its location.
|
|
||||||
func NewVenue(chatID int64, title, address string, latitude, longitude float64) VenueConfig {
|
|
||||||
return VenueConfig{
|
|
||||||
BaseChat: BaseChat{
|
|
||||||
ChatID: chatID,
|
|
||||||
},
|
|
||||||
Title: title,
|
|
||||||
Address: address,
|
|
||||||
Latitude: latitude,
|
|
||||||
Longitude: longitude,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewChatAction sets a chat action.
|
|
||||||
// Actions last for 5 seconds, or until your next action.
|
|
||||||
//
|
|
||||||
// chatID is where to send it, action should be set via Chat constants.
|
|
||||||
func NewChatAction(chatID int64, action string) ChatActionConfig {
|
|
||||||
return ChatActionConfig{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
Action: action,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUserProfilePhotos gets user profile photos.
|
|
||||||
//
|
|
||||||
// userID is the ID of the user you wish to get profile photos from.
|
|
||||||
func NewUserProfilePhotos(userID int) UserProfilePhotosConfig {
|
|
||||||
return UserProfilePhotosConfig{
|
|
||||||
UserID: userID,
|
|
||||||
Offset: 0,
|
|
||||||
Limit: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUpdate gets updates since the last Offset.
|
|
||||||
//
|
|
||||||
// offset is the last Update ID to include.
|
|
||||||
// You likely want to set this to the last Update ID plus 1.
|
|
||||||
func NewUpdate(offset int) UpdateConfig {
|
|
||||||
return UpdateConfig{
|
|
||||||
Offset: offset,
|
|
||||||
Limit: 0,
|
|
||||||
Timeout: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWebhook creates a new webhook.
|
|
||||||
//
|
|
||||||
// link is the url parsable link you wish to get the updates.
|
|
||||||
func NewWebhook(link string) WebhookConfig {
|
|
||||||
u, _ := url.Parse(link)
|
|
||||||
|
|
||||||
return WebhookConfig{
|
|
||||||
URL: u,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewWebhookWithCert creates a new webhook with a certificate.
|
|
||||||
//
|
|
||||||
// link is the url you wish to get webhooks,
|
|
||||||
// file contains a string to a file, FileReader, or FileBytes.
|
|
||||||
func NewWebhookWithCert(link string, file interface{}) WebhookConfig {
|
|
||||||
u, _ := url.Parse(link)
|
|
||||||
|
|
||||||
return WebhookConfig{
|
|
||||||
URL: u,
|
|
||||||
Certificate: file,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultArticle creates a new inline query article.
|
|
||||||
func NewInlineQueryResultArticle(id, title, messageText string) InlineQueryResultArticle {
|
|
||||||
return InlineQueryResultArticle{
|
|
||||||
Type: "article",
|
|
||||||
ID: id,
|
|
||||||
Title: title,
|
|
||||||
InputMessageContent: InputTextMessageContent{
|
|
||||||
Text: messageText,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultArticleMarkdown creates a new inline query article with Markdown parsing.
|
|
||||||
func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQueryResultArticle {
|
|
||||||
return InlineQueryResultArticle{
|
|
||||||
Type: "article",
|
|
||||||
ID: id,
|
|
||||||
Title: title,
|
|
||||||
InputMessageContent: InputTextMessageContent{
|
|
||||||
Text: messageText,
|
|
||||||
ParseMode: "Markdown",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
|
||||||
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
|
||||||
return InlineQueryResultArticle{
|
|
||||||
Type: "article",
|
|
||||||
ID: id,
|
|
||||||
Title: title,
|
|
||||||
InputMessageContent: InputTextMessageContent{
|
|
||||||
Text: messageText,
|
|
||||||
ParseMode: "HTML",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultGIF creates a new inline query GIF.
|
|
||||||
func NewInlineQueryResultGIF(id, url string) InlineQueryResultGIF {
|
|
||||||
return InlineQueryResultGIF{
|
|
||||||
Type: "gif",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF.
|
|
||||||
func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
|
||||||
return InlineQueryResultMPEG4GIF{
|
|
||||||
Type: "mpeg4_gif",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultPhoto creates a new inline query photo.
|
|
||||||
func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto {
|
|
||||||
return InlineQueryResultPhoto{
|
|
||||||
Type: "photo",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultPhotoWithThumb creates a new inline query photo.
|
|
||||||
func NewInlineQueryResultPhotoWithThumb(id, url, thumb string) InlineQueryResultPhoto {
|
|
||||||
return InlineQueryResultPhoto{
|
|
||||||
Type: "photo",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
ThumbURL: thumb,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultVideo creates a new inline query video.
|
|
||||||
func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo {
|
|
||||||
return InlineQueryResultVideo{
|
|
||||||
Type: "video",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultAudio creates a new inline query audio.
|
|
||||||
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
|
||||||
return InlineQueryResultAudio{
|
|
||||||
Type: "audio",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
Title: title,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultVoice creates a new inline query voice.
|
|
||||||
func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice {
|
|
||||||
return InlineQueryResultVoice{
|
|
||||||
Type: "voice",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
Title: title,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultDocument creates a new inline query document.
|
|
||||||
func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument {
|
|
||||||
return InlineQueryResultDocument{
|
|
||||||
Type: "document",
|
|
||||||
ID: id,
|
|
||||||
URL: url,
|
|
||||||
Title: title,
|
|
||||||
MimeType: mimeType,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineQueryResultLocation creates a new inline query location.
|
|
||||||
func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation {
|
|
||||||
return InlineQueryResultLocation{
|
|
||||||
Type: "location",
|
|
||||||
ID: id,
|
|
||||||
Title: title,
|
|
||||||
Latitude: latitude,
|
|
||||||
Longitude: longitude,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEditMessageText allows you to edit the text of a message.
|
|
||||||
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
|
|
||||||
return EditMessageTextConfig{
|
|
||||||
BaseEdit: BaseEdit{
|
|
||||||
ChatID: chatID,
|
|
||||||
MessageID: messageID,
|
|
||||||
},
|
|
||||||
Text: text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEditMessageCaption allows you to edit the caption of a message.
|
|
||||||
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
|
||||||
return EditMessageCaptionConfig{
|
|
||||||
BaseEdit: BaseEdit{
|
|
||||||
ChatID: chatID,
|
|
||||||
MessageID: messageID,
|
|
||||||
},
|
|
||||||
Caption: caption,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEditMessageReplyMarkup allows you to edit the inline
|
|
||||||
// keyboard markup.
|
|
||||||
func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig {
|
|
||||||
return EditMessageReplyMarkupConfig{
|
|
||||||
BaseEdit: BaseEdit{
|
|
||||||
ChatID: chatID,
|
|
||||||
MessageID: messageID,
|
|
||||||
ReplyMarkup: &replyMarkup,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHideKeyboard hides the keyboard, with the option for being selective
|
|
||||||
// or hiding for everyone.
|
|
||||||
func NewHideKeyboard(selective bool) ReplyKeyboardHide {
|
|
||||||
log.Println("NewHideKeyboard is deprecated, please use NewRemoveKeyboard")
|
|
||||||
|
|
||||||
return ReplyKeyboardHide{
|
|
||||||
HideKeyboard: true,
|
|
||||||
Selective: selective,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRemoveKeyboard hides the keyboard, with the option for being selective
|
|
||||||
// or hiding for everyone.
|
|
||||||
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {
|
|
||||||
return ReplyKeyboardRemove{
|
|
||||||
RemoveKeyboard: true,
|
|
||||||
Selective: selective,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyboardButton creates a regular keyboard button.
|
|
||||||
func NewKeyboardButton(text string) KeyboardButton {
|
|
||||||
return KeyboardButton{
|
|
||||||
Text: text,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyboardButtonContact creates a keyboard button that requests
|
|
||||||
// user contact information upon click.
|
|
||||||
func NewKeyboardButtonContact(text string) KeyboardButton {
|
|
||||||
return KeyboardButton{
|
|
||||||
Text: text,
|
|
||||||
RequestContact: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyboardButtonLocation creates a keyboard button that requests
|
|
||||||
// user location information upon click.
|
|
||||||
func NewKeyboardButtonLocation(text string) KeyboardButton {
|
|
||||||
return KeyboardButton{
|
|
||||||
Text: text,
|
|
||||||
RequestLocation: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewKeyboardButtonRow creates a row of keyboard buttons.
|
|
||||||
func NewKeyboardButtonRow(buttons ...KeyboardButton) []KeyboardButton {
|
|
||||||
var row []KeyboardButton
|
|
||||||
|
|
||||||
row = append(row, buttons...)
|
|
||||||
|
|
||||||
return row
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReplyKeyboard creates a new regular keyboard with sane defaults.
|
|
||||||
func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
|
||||||
var keyboard [][]KeyboardButton
|
|
||||||
|
|
||||||
keyboard = append(keyboard, rows...)
|
|
||||||
|
|
||||||
return ReplyKeyboardMarkup{
|
|
||||||
ResizeKeyboard: true,
|
|
||||||
Keyboard: keyboard,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
|
||||||
// and data for a callback.
|
|
||||||
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
|
||||||
return InlineKeyboardButton{
|
|
||||||
Text: text,
|
|
||||||
CallbackData: &data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineKeyboardButtonURL creates an inline keyboard button with text
|
|
||||||
// which goes to a URL.
|
|
||||||
func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton {
|
|
||||||
return InlineKeyboardButton{
|
|
||||||
Text: text,
|
|
||||||
URL: &url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineKeyboardButtonSwitch creates an inline keyboard button with
|
|
||||||
// text which allows the user to switch to a chat or return to a chat.
|
|
||||||
func NewInlineKeyboardButtonSwitch(text, sw string) InlineKeyboardButton {
|
|
||||||
return InlineKeyboardButton{
|
|
||||||
Text: text,
|
|
||||||
SwitchInlineQuery: &sw,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineKeyboardRow creates an inline keyboard row with buttons.
|
|
||||||
func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton {
|
|
||||||
var row []InlineKeyboardButton
|
|
||||||
|
|
||||||
row = append(row, buttons...)
|
|
||||||
|
|
||||||
return row
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInlineKeyboardMarkup creates a new inline keyboard.
|
|
||||||
func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) InlineKeyboardMarkup {
|
|
||||||
var keyboard [][]InlineKeyboardButton
|
|
||||||
|
|
||||||
keyboard = append(keyboard, rows...)
|
|
||||||
|
|
||||||
return InlineKeyboardMarkup{
|
|
||||||
InlineKeyboard: keyboard,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCallback creates a new callback message.
|
|
||||||
func NewCallback(id, text string) CallbackConfig {
|
|
||||||
return CallbackConfig{
|
|
||||||
CallbackQueryID: id,
|
|
||||||
Text: text,
|
|
||||||
ShowAlert: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCallbackWithAlert creates a new callback message that alerts
|
|
||||||
// the user.
|
|
||||||
func NewCallbackWithAlert(id, text string) CallbackConfig {
|
|
||||||
return CallbackConfig{
|
|
||||||
CallbackQueryID: id,
|
|
||||||
Text: text,
|
|
||||||
ShowAlert: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInvoice created a new Invoice request to the user.
|
|
||||||
func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices *[]LabeledPrice) InvoiceConfig {
|
|
||||||
return InvoiceConfig{
|
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
|
||||||
Title: title,
|
|
||||||
Description: description,
|
|
||||||
Payload: payload,
|
|
||||||
ProviderToken: providerToken,
|
|
||||||
StartParameter: startParameter,
|
|
||||||
Currency: currency,
|
|
||||||
Prices: prices}
|
|
||||||
}
|
|
773
vendor/gopkg.in/telegram-bot-api.v4/types.go
generated
vendored
773
vendor/gopkg.in/telegram-bot-api.v4/types.go
generated
vendored
@ -1,773 +0,0 @@
|
|||||||
package tgbotapi
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// APIResponse is a response from the Telegram API with the result
|
|
||||||
// stored raw.
|
|
||||||
type APIResponse struct {
|
|
||||||
Ok bool `json:"ok"`
|
|
||||||
Result json.RawMessage `json:"result"`
|
|
||||||
ErrorCode int `json:"error_code"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Parameters *ResponseParameters `json:"parameters"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResponseParameters are various errors that can be returned in APIResponse.
|
|
||||||
type ResponseParameters struct {
|
|
||||||
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
|
||||||
RetryAfter int `json:"retry_after"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update is an update response, from GetUpdates.
|
|
||||||
type Update struct {
|
|
||||||
UpdateID int `json:"update_id"`
|
|
||||||
Message *Message `json:"message"`
|
|
||||||
EditedMessage *Message `json:"edited_message"`
|
|
||||||
ChannelPost *Message `json:"channel_post"`
|
|
||||||
EditedChannelPost *Message `json:"edited_channel_post"`
|
|
||||||
InlineQuery *InlineQuery `json:"inline_query"`
|
|
||||||
ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"`
|
|
||||||
CallbackQuery *CallbackQuery `json:"callback_query"`
|
|
||||||
ShippingQuery *ShippingQuery `json:"shipping_query"`
|
|
||||||
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdatesChannel is the channel for getting updates.
|
|
||||||
type UpdatesChannel <-chan Update
|
|
||||||
|
|
||||||
// Clear discards all unprocessed incoming updates.
|
|
||||||
func (ch UpdatesChannel) Clear() {
|
|
||||||
for len(ch) != 0 {
|
|
||||||
<-ch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// User is a user on Telegram.
|
|
||||||
type User struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"` // optional
|
|
||||||
UserName string `json:"username"` // optional
|
|
||||||
LanguageCode string `json:"language_code"` // optional
|
|
||||||
IsBot bool `json:"is_bot"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// String displays a simple text version of a user.
|
|
||||||
//
|
|
||||||
// It is normally a user's username, but falls back to a first/last
|
|
||||||
// name as available.
|
|
||||||
func (u *User) String() string {
|
|
||||||
if u.UserName != "" {
|
|
||||||
return u.UserName
|
|
||||||
}
|
|
||||||
|
|
||||||
name := u.FirstName
|
|
||||||
if u.LastName != "" {
|
|
||||||
name += " " + u.LastName
|
|
||||||
}
|
|
||||||
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// GroupChat is a group chat.
|
|
||||||
type GroupChat struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatPhoto represents a chat photo.
|
|
||||||
type ChatPhoto struct {
|
|
||||||
SmallFileID string `json:"small_file_id"`
|
|
||||||
BigFileID string `json:"big_file_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chat contains information about the place a message was sent.
|
|
||||||
type Chat struct {
|
|
||||||
ID int64 `json:"id"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Title string `json:"title"` // optional
|
|
||||||
UserName string `json:"username"` // optional
|
|
||||||
FirstName string `json:"first_name"` // optional
|
|
||||||
LastName string `json:"last_name"` // optional
|
|
||||||
AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional
|
|
||||||
Photo *ChatPhoto `json:"photo"`
|
|
||||||
Description string `json:"description,omitempty"` // optional
|
|
||||||
InviteLink string `json:"invite_link,omitempty"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPrivate returns if the Chat is a private conversation.
|
|
||||||
func (c Chat) IsPrivate() bool {
|
|
||||||
return c.Type == "private"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsGroup returns if the Chat is a group.
|
|
||||||
func (c Chat) IsGroup() bool {
|
|
||||||
return c.Type == "group"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSuperGroup returns if the Chat is a supergroup.
|
|
||||||
func (c Chat) IsSuperGroup() bool {
|
|
||||||
return c.Type == "supergroup"
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsChannel returns if the Chat is a channel.
|
|
||||||
func (c Chat) IsChannel() bool {
|
|
||||||
return c.Type == "channel"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatConfig returns a ChatConfig struct for chat related methods.
|
|
||||||
func (c Chat) ChatConfig() ChatConfig {
|
|
||||||
return ChatConfig{ChatID: c.ID}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message is returned by almost every request, and contains data about
|
|
||||||
// almost anything.
|
|
||||||
type Message struct {
|
|
||||||
MessageID int `json:"message_id"`
|
|
||||||
From *User `json:"from"` // optional
|
|
||||||
Date int `json:"date"`
|
|
||||||
Chat *Chat `json:"chat"`
|
|
||||||
ForwardFrom *User `json:"forward_from"` // optional
|
|
||||||
ForwardFromChat *Chat `json:"forward_from_chat"` // optional
|
|
||||||
ForwardFromMessageID int `json:"forward_from_message_id"` // optional
|
|
||||||
ForwardDate int `json:"forward_date"` // optional
|
|
||||||
ReplyToMessage *Message `json:"reply_to_message"` // optional
|
|
||||||
EditDate int `json:"edit_date"` // optional
|
|
||||||
Text string `json:"text"` // optional
|
|
||||||
Entities *[]MessageEntity `json:"entities"` // optional
|
|
||||||
Audio *Audio `json:"audio"` // optional
|
|
||||||
Document *Document `json:"document"` // optional
|
|
||||||
Game *Game `json:"game"` // optional
|
|
||||||
Photo *[]PhotoSize `json:"photo"` // optional
|
|
||||||
Sticker *Sticker `json:"sticker"` // optional
|
|
||||||
Video *Video `json:"video"` // optional
|
|
||||||
VideoNote *VideoNote `json:"video_note"` // optional
|
|
||||||
Voice *Voice `json:"voice"` // optional
|
|
||||||
Caption string `json:"caption"` // optional
|
|
||||||
Contact *Contact `json:"contact"` // optional
|
|
||||||
Location *Location `json:"location"` // optional
|
|
||||||
Venue *Venue `json:"venue"` // optional
|
|
||||||
NewChatMembers *[]User `json:"new_chat_members"` // optional
|
|
||||||
LeftChatMember *User `json:"left_chat_member"` // optional
|
|
||||||
NewChatTitle string `json:"new_chat_title"` // optional
|
|
||||||
NewChatPhoto *[]PhotoSize `json:"new_chat_photo"` // optional
|
|
||||||
DeleteChatPhoto bool `json:"delete_chat_photo"` // optional
|
|
||||||
GroupChatCreated bool `json:"group_chat_created"` // optional
|
|
||||||
SuperGroupChatCreated bool `json:"supergroup_chat_created"` // optional
|
|
||||||
ChannelChatCreated bool `json:"channel_chat_created"` // optional
|
|
||||||
MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional
|
|
||||||
MigrateFromChatID int64 `json:"migrate_from_chat_id"` // optional
|
|
||||||
PinnedMessage *Message `json:"pinned_message"` // optional
|
|
||||||
Invoice *Invoice `json:"invoice"` // optional
|
|
||||||
SuccessfulPayment *SuccessfulPayment `json:"successful_payment"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time converts the message timestamp into a Time.
|
|
||||||
func (m *Message) Time() time.Time {
|
|
||||||
return time.Unix(int64(m.Date), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCommand returns true if message starts with a "bot_command" entity.
|
|
||||||
func (m *Message) IsCommand() bool {
|
|
||||||
if m.Entities == nil || len(*m.Entities) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
entity := (*m.Entities)[0]
|
|
||||||
return entity.Offset == 0 && entity.Type == "bot_command"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command checks if the message was a command and if it was, returns the
|
|
||||||
// command. If the Message was not a command, it returns an empty string.
|
|
||||||
//
|
|
||||||
// If the command contains the at name syntax, it is removed. Use
|
|
||||||
// CommandWithAt() if you do not want that.
|
|
||||||
func (m *Message) Command() string {
|
|
||||||
command := m.CommandWithAt()
|
|
||||||
|
|
||||||
if i := strings.Index(command, "@"); i != -1 {
|
|
||||||
command = command[:i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return command
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandWithAt checks if the message was a command and if it was, returns the
|
|
||||||
// command. If the Message was not a command, it returns an empty string.
|
|
||||||
//
|
|
||||||
// If the command contains the at name syntax, it is not removed. Use Command()
|
|
||||||
// if you want that.
|
|
||||||
func (m *Message) CommandWithAt() string {
|
|
||||||
if !m.IsCommand() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCommand() checks that the message begins with a bot_command entity
|
|
||||||
entity := (*m.Entities)[0]
|
|
||||||
return m.Text[1:entity.Length]
|
|
||||||
}
|
|
||||||
|
|
||||||
// CommandArguments checks if the message was a command and if it was,
|
|
||||||
// returns all text after the command name. If the Message was not a
|
|
||||||
// command, it returns an empty string.
|
|
||||||
//
|
|
||||||
// Note: The first character after the command name is omitted:
|
|
||||||
// - "/foo bar baz" yields "bar baz", not " bar baz"
|
|
||||||
// - "/foo-bar baz" yields "bar baz", too
|
|
||||||
// Even though the latter is not a command conforming to the spec, the API
|
|
||||||
// marks "/foo" as command entity.
|
|
||||||
func (m *Message) CommandArguments() string {
|
|
||||||
if !m.IsCommand() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCommand() checks that the message begins with a bot_command entity
|
|
||||||
entity := (*m.Entities)[0]
|
|
||||||
if len(m.Text) == entity.Length {
|
|
||||||
return "" // The command makes up the whole message
|
|
||||||
} else {
|
|
||||||
return m.Text[entity.Length+1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageEntity contains information about data in a Message.
|
|
||||||
type MessageEntity struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Offset int `json:"offset"`
|
|
||||||
Length int `json:"length"`
|
|
||||||
URL string `json:"url"` // optional
|
|
||||||
User *User `json:"user"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseURL attempts to parse a URL contained within a MessageEntity.
|
|
||||||
func (entity MessageEntity) ParseURL() (*url.URL, error) {
|
|
||||||
if entity.URL == "" {
|
|
||||||
return nil, errors.New(ErrBadURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.Parse(entity.URL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PhotoSize contains information about photos.
|
|
||||||
type PhotoSize struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Width int `json:"width"`
|
|
||||||
Height int `json:"height"`
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Audio contains information about audio.
|
|
||||||
type Audio struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
Performer string `json:"performer"` // optional
|
|
||||||
Title string `json:"title"` // optional
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Document contains information about a document.
|
|
||||||
type Document struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
|
||||||
FileName string `json:"file_name"` // optional
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sticker contains information about a sticker.
|
|
||||||
type Sticker struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Width int `json:"width"`
|
|
||||||
Height int `json:"height"`
|
|
||||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
|
||||||
Emoji string `json:"emoji"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Video contains information about a video.
|
|
||||||
type Video struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Width int `json:"width"`
|
|
||||||
Height int `json:"height"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// VideoNote contains information about a video.
|
|
||||||
type VideoNote struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Length int `json:"length"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
Thumbnail *PhotoSize `json:"thumb"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Voice contains information about a voice.
|
|
||||||
type Voice struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
MimeType string `json:"mime_type"` // optional
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contact contains information about a contact.
|
|
||||||
//
|
|
||||||
// Note that LastName and UserID may be empty.
|
|
||||||
type Contact struct {
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"` // optional
|
|
||||||
UserID int `json:"user_id"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Location contains information about a place.
|
|
||||||
type Location struct {
|
|
||||||
Longitude float64 `json:"longitude"`
|
|
||||||
Latitude float64 `json:"latitude"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Venue contains information about a venue, including its Location.
|
|
||||||
type Venue struct {
|
|
||||||
Location Location `json:"location"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
FoursquareID string `json:"foursquare_id"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserProfilePhotos contains a set of user profile photos.
|
|
||||||
type UserProfilePhotos struct {
|
|
||||||
TotalCount int `json:"total_count"`
|
|
||||||
Photos [][]PhotoSize `json:"photos"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// File contains information about a file to download from Telegram.
|
|
||||||
type File struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
FileSize int `json:"file_size"` // optional
|
|
||||||
FilePath string `json:"file_path"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link returns a full path to the download URL for a File.
|
|
||||||
//
|
|
||||||
// It requires the Bot Token to create the link.
|
|
||||||
func (f *File) Link(token string) string {
|
|
||||||
return fmt.Sprintf(FileEndpoint, token, f.FilePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
|
|
||||||
type ReplyKeyboardMarkup struct {
|
|
||||||
Keyboard [][]KeyboardButton `json:"keyboard"`
|
|
||||||
ResizeKeyboard bool `json:"resize_keyboard"` // optional
|
|
||||||
OneTimeKeyboard bool `json:"one_time_keyboard"` // optional
|
|
||||||
Selective bool `json:"selective"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyboardButton is a button within a custom keyboard.
|
|
||||||
type KeyboardButton struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
RequestContact bool `json:"request_contact"`
|
|
||||||
RequestLocation bool `json:"request_location"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
|
|
||||||
type ReplyKeyboardHide struct {
|
|
||||||
HideKeyboard bool `json:"hide_keyboard"`
|
|
||||||
Selective bool `json:"selective"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplyKeyboardRemove allows the Bot to hide a custom keyboard.
|
|
||||||
type ReplyKeyboardRemove struct {
|
|
||||||
RemoveKeyboard bool `json:"remove_keyboard"`
|
|
||||||
Selective bool `json:"selective"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineKeyboardMarkup is a custom keyboard presented for an inline bot.
|
|
||||||
type InlineKeyboardMarkup struct {
|
|
||||||
InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineKeyboardButton is a button within a custom keyboard for
|
|
||||||
// inline query responses.
|
|
||||||
//
|
|
||||||
// Note that some values are references as even an empty string
|
|
||||||
// will change behavior.
|
|
||||||
//
|
|
||||||
// CallbackGame, if set, MUST be first button in first row.
|
|
||||||
type InlineKeyboardButton struct {
|
|
||||||
Text string `json:"text"`
|
|
||||||
URL *string `json:"url,omitempty"` // optional
|
|
||||||
CallbackData *string `json:"callback_data,omitempty"` // optional
|
|
||||||
SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
|
|
||||||
SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat,omitempty"` // optional
|
|
||||||
CallbackGame *CallbackGame `json:"callback_game,omitempty"` // optional
|
|
||||||
Pay bool `json:"pay,omitempty"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallbackQuery is data sent when a keyboard button with callback data
|
|
||||||
// is clicked.
|
|
||||||
type CallbackQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Message *Message `json:"message"` // optional
|
|
||||||
InlineMessageID string `json:"inline_message_id"` // optional
|
|
||||||
ChatInstance string `json:"chat_instance"`
|
|
||||||
Data string `json:"data"` // optional
|
|
||||||
GameShortName string `json:"game_short_name"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForceReply allows the Bot to have users directly reply to it without
|
|
||||||
// additional interaction.
|
|
||||||
type ForceReply struct {
|
|
||||||
ForceReply bool `json:"force_reply"`
|
|
||||||
Selective bool `json:"selective"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatMember is information about a member in a chat.
|
|
||||||
type ChatMember struct {
|
|
||||||
User *User `json:"user"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
UntilDate int64 `json:"until_date,omitempty"` // optional
|
|
||||||
CanBeEdited bool `json:"can_be_edited,omitempty"` // optional
|
|
||||||
CanChangeInfo bool `json:"can_change_info,omitempty"` // optional
|
|
||||||
CanPostMessages bool `json:"can_post_messages,omitempty"` // optional
|
|
||||||
CanEditMessages bool `json:"can_edit_messages,omitempty"` // optional
|
|
||||||
CanDeleteMessages bool `json:"can_delete_messages,omitempty"` // optional
|
|
||||||
CanInviteUsers bool `json:"can_invite_users,omitempty"` // optional
|
|
||||||
CanRestrictMembers bool `json:"can_restrict_members,omitempty"` // optional
|
|
||||||
CanPinMessages bool `json:"can_pin_messages,omitempty"` // optional
|
|
||||||
CanPromoteMembers bool `json:"can_promote_members,omitempty"` // optional
|
|
||||||
CanSendMessages bool `json:"can_send_messages,omitempty"` // optional
|
|
||||||
CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` // optional
|
|
||||||
CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` // optional
|
|
||||||
CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCreator returns if the ChatMember was the creator of the chat.
|
|
||||||
func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" }
|
|
||||||
|
|
||||||
// IsAdministrator returns if the ChatMember is a chat administrator.
|
|
||||||
func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" }
|
|
||||||
|
|
||||||
// IsMember returns if the ChatMember is a current member of the chat.
|
|
||||||
func (chat ChatMember) IsMember() bool { return chat.Status == "member" }
|
|
||||||
|
|
||||||
// HasLeft returns if the ChatMember left the chat.
|
|
||||||
func (chat ChatMember) HasLeft() bool { return chat.Status == "left" }
|
|
||||||
|
|
||||||
// WasKicked returns if the ChatMember was kicked from the chat.
|
|
||||||
func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" }
|
|
||||||
|
|
||||||
// Game is a game within Telegram.
|
|
||||||
type Game struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Photo []PhotoSize `json:"photo"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
TextEntities []MessageEntity `json:"text_entities"`
|
|
||||||
Animation Animation `json:"animation"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Animation is a GIF animation demonstrating the game.
|
|
||||||
type Animation struct {
|
|
||||||
FileID string `json:"file_id"`
|
|
||||||
Thumb PhotoSize `json:"thumb"`
|
|
||||||
FileName string `json:"file_name"`
|
|
||||||
MimeType string `json:"mime_type"`
|
|
||||||
FileSize int `json:"file_size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GameHighScore is a user's score and position on the leaderboard.
|
|
||||||
type GameHighScore struct {
|
|
||||||
Position int `json:"position"`
|
|
||||||
User User `json:"user"`
|
|
||||||
Score int `json:"score"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallbackGame is for starting a game in an inline keyboard button.
|
|
||||||
type CallbackGame struct{}
|
|
||||||
|
|
||||||
// WebhookInfo is information about a currently set webhook.
|
|
||||||
type WebhookInfo struct {
|
|
||||||
URL string `json:"url"`
|
|
||||||
HasCustomCertificate bool `json:"has_custom_certificate"`
|
|
||||||
PendingUpdateCount int `json:"pending_update_count"`
|
|
||||||
LastErrorDate int `json:"last_error_date"` // optional
|
|
||||||
LastErrorMessage string `json:"last_error_message"` // optional
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSet returns true if a webhook is currently set.
|
|
||||||
func (info WebhookInfo) IsSet() bool {
|
|
||||||
return info.URL != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQuery is a Query from Telegram for an inline request.
|
|
||||||
type InlineQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Location *Location `json:"location"` // optional
|
|
||||||
Query string `json:"query"`
|
|
||||||
Offset string `json:"offset"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultArticle is an inline query response article.
|
|
||||||
type InlineQueryResultArticle struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"` // required
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
HideURL bool `json:"hide_url"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
ThumbWidth int `json:"thumb_width"`
|
|
||||||
ThumbHeight int `json:"thumb_height"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultPhoto is an inline query response photo.
|
|
||||||
type InlineQueryResultPhoto struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"photo_url"` // required
|
|
||||||
MimeType string `json:"mime_type"`
|
|
||||||
Width int `json:"photo_width"`
|
|
||||||
Height int `json:"photo_height"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultGIF is an inline query response GIF.
|
|
||||||
type InlineQueryResultGIF struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"gif_url"` // required
|
|
||||||
Width int `json:"gif_width"`
|
|
||||||
Height int `json:"gif_height"`
|
|
||||||
Duration int `json:"gif_duration"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF.
|
|
||||||
type InlineQueryResultMPEG4GIF struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"mpeg4_url"` // required
|
|
||||||
Width int `json:"mpeg4_width"`
|
|
||||||
Height int `json:"mpeg4_height"`
|
|
||||||
Duration int `json:"mpeg4_duration"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultVideo is an inline query response video.
|
|
||||||
type InlineQueryResultVideo struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"video_url"` // required
|
|
||||||
MimeType string `json:"mime_type"` // required
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Width int `json:"video_width"`
|
|
||||||
Height int `json:"video_height"`
|
|
||||||
Duration int `json:"video_duration"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultAudio is an inline query response audio.
|
|
||||||
type InlineQueryResultAudio struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"audio_url"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Performer string `json:"performer"`
|
|
||||||
Duration int `json:"audio_duration"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultVoice is an inline query response voice.
|
|
||||||
type InlineQueryResultVoice struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
URL string `json:"voice_url"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
Duration int `json:"voice_duration"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultDocument is an inline query response document.
|
|
||||||
type InlineQueryResultDocument struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
Caption string `json:"caption"`
|
|
||||||
URL string `json:"document_url"` // required
|
|
||||||
MimeType string `json:"mime_type"` // required
|
|
||||||
Description string `json:"description"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
ThumbWidth int `json:"thumb_width"`
|
|
||||||
ThumbHeight int `json:"thumb_height"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultLocation is an inline query response location.
|
|
||||||
type InlineQueryResultLocation struct {
|
|
||||||
Type string `json:"type"` // required
|
|
||||||
ID string `json:"id"` // required
|
|
||||||
Latitude float64 `json:"latitude"` // required
|
|
||||||
Longitude float64 `json:"longitude"` // required
|
|
||||||
Title string `json:"title"` // required
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
|
||||||
InputMessageContent interface{} `json:"input_message_content,omitempty"`
|
|
||||||
ThumbURL string `json:"thumb_url"`
|
|
||||||
ThumbWidth int `json:"thumb_width"`
|
|
||||||
ThumbHeight int `json:"thumb_height"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InlineQueryResultGame is an inline query response game.
|
|
||||||
type InlineQueryResultGame struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
GameShortName string `json:"game_short_name"`
|
|
||||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChosenInlineResult is an inline query result chosen by a User
|
|
||||||
type ChosenInlineResult struct {
|
|
||||||
ResultID string `json:"result_id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Location *Location `json:"location"`
|
|
||||||
InlineMessageID string `json:"inline_message_id"`
|
|
||||||
Query string `json:"query"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputTextMessageContent contains text for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputTextMessageContent struct {
|
|
||||||
Text string `json:"message_text"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
DisableWebPagePreview bool `json:"disable_web_page_preview"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputLocationMessageContent contains a location for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputLocationMessageContent struct {
|
|
||||||
Latitude float64 `json:"latitude"`
|
|
||||||
Longitude float64 `json:"longitude"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputVenueMessageContent contains a venue for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputVenueMessageContent struct {
|
|
||||||
Latitude float64 `json:"latitude"`
|
|
||||||
Longitude float64 `json:"longitude"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Address string `json:"address"`
|
|
||||||
FoursquareID string `json:"foursquare_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// InputContactMessageContent contains a contact for displaying
|
|
||||||
// as an inline query result.
|
|
||||||
type InputContactMessageContent struct {
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoice contains basic information about an invoice.
|
|
||||||
type Invoice struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
StartParameter string `json:"start_parameter"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
TotalAmount int `json:"total_amount"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LabeledPrice represents a portion of the price for goods or services.
|
|
||||||
type LabeledPrice struct {
|
|
||||||
Label string `json:"label"`
|
|
||||||
Amount int `json:"amount"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShippingAddress represents a shipping address.
|
|
||||||
type ShippingAddress struct {
|
|
||||||
CountryCode string `json:"country_code"`
|
|
||||||
State string `json:"state"`
|
|
||||||
City string `json:"city"`
|
|
||||||
StreetLine1 string `json:"street_line1"`
|
|
||||||
StreetLine2 string `json:"street_line2"`
|
|
||||||
PostCode string `json:"post_code"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OrderInfo represents information about an order.
|
|
||||||
type OrderInfo struct {
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
PhoneNumber string `json:"phone_number,omitempty"`
|
|
||||||
Email string `json:"email,omitempty"`
|
|
||||||
ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShippingOption represents one shipping option.
|
|
||||||
type ShippingOption struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Prices *[]LabeledPrice `json:"prices"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SuccessfulPayment contains basic information about a successful payment.
|
|
||||||
type SuccessfulPayment struct {
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
TotalAmount int `json:"total_amount"`
|
|
||||||
InvoicePayload string `json:"invoice_payload"`
|
|
||||||
ShippingOptionID string `json:"shipping_option_id,omitempty"`
|
|
||||||
OrderInfo *OrderInfo `json:"order_info,omitempty"`
|
|
||||||
TelegramPaymentChargeID string `json:"telegram_payment_charge_id"`
|
|
||||||
ProviderPaymentChargeID string `json:"provider_payment_charge_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShippingQuery contains information about an incoming shipping query.
|
|
||||||
type ShippingQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
InvoicePayload string `json:"invoice_payload"`
|
|
||||||
ShippingAddress *ShippingAddress `json:"shipping_address"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PreCheckoutQuery contains information about an incoming pre-checkout query.
|
|
||||||
type PreCheckoutQuery struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
From *User `json:"from"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
TotalAmount int `json:"total_amount"`
|
|
||||||
InvoicePayload string `json:"invoice_payload"`
|
|
||||||
ShippingOptionID string `json:"shipping_option_id,omitempty"`
|
|
||||||
OrderInfo *OrderInfo `json:"order_info,omitempty"`
|
|
||||||
}
|
|
85
vendor/vendor.json
vendored
85
vendor/vendor.json
vendored
@ -1,85 +0,0 @@
|
|||||||
{
|
|
||||||
"comment": "",
|
|
||||||
"ignore": "test",
|
|
||||||
"package": [
|
|
||||||
{
|
|
||||||
"checksumSHA1": "oQOyaNHROmz71BmWcxEdVJJ1bTM=",
|
|
||||||
"path": "github.com/appleboy/drone-facebook/template",
|
|
||||||
"revision": "fdda56ebba0f6ab0627f6308612a9e76c6ac6abd",
|
|
||||||
"revisionTime": "2017-04-30T10:16:16Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "PZ4KJai7DnuJ2YNJ2v2l2BseB1g=",
|
|
||||||
"path": "github.com/aymerick/raymond",
|
|
||||||
"revision": "72acac2207479d21dd45898c2a4264246c818148",
|
|
||||||
"revisionTime": "2016-12-09T22:07:24Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "Rvn+RH9pwFno1w6W+mhWsj/PxlA=",
|
|
||||||
"path": "github.com/aymerick/raymond/ast",
|
|
||||||
"revision": "72acac2207479d21dd45898c2a4264246c818148",
|
|
||||||
"revisionTime": "2016-12-09T22:07:24Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "5SJwPK0MYtJt5YiE1BNc9Wl3+S0=",
|
|
||||||
"path": "github.com/aymerick/raymond/lexer",
|
|
||||||
"revision": "72acac2207479d21dd45898c2a4264246c818148",
|
|
||||||
"revisionTime": "2016-12-09T22:07:24Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "TCu/8QBP8TApLjSt13a7Qjnyxrs=",
|
|
||||||
"path": "github.com/aymerick/raymond/parser",
|
|
||||||
"revision": "72acac2207479d21dd45898c2a4264246c818148",
|
|
||||||
"revisionTime": "2016-12-09T22:07:24Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "7UT+dVVfOn8IA79ITFiGNMb2c/4=",
|
|
||||||
"path": "github.com/davecgh/go-spew/spew",
|
|
||||||
"revision": "782f4967f2dc4564575ca782fe2d04090b5faca8",
|
|
||||||
"revisionTime": "2017-06-26T23:16:45Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "qzl/TNo4WnfR+PZRfk3iFHg68sM=",
|
|
||||||
"path": "github.com/joho/godotenv",
|
|
||||||
"revision": "325433c502d409f3c3dc820098fb0cfe38d98dc7",
|
|
||||||
"revisionTime": "2017-03-28T20:01:54Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "UE4lhbPYYWEhqHXQk24OA73m5+8=",
|
|
||||||
"path": "github.com/joho/godotenv/autoload",
|
|
||||||
"revision": "325433c502d409f3c3dc820098fb0cfe38d98dc7",
|
|
||||||
"revisionTime": "2017-03-28T20:01:54Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "LuFv4/jlrmFNnDb/5SCSEPAM9vU=",
|
|
||||||
"path": "github.com/pmezard/go-difflib/difflib",
|
|
||||||
"revision": "792786c7400a136282c1664665ae0a8db921c6c2",
|
|
||||||
"revisionTime": "2016-01-10T10:55:54Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "5NBHAe3S15q3L9hOLThnMZjIZRE=",
|
|
||||||
"path": "github.com/stretchr/testify/assert",
|
|
||||||
"revision": "f6abca593680b2315d2075e0f5e2a9751e3f431a",
|
|
||||||
"revisionTime": "2017-06-01T20:57:54Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "t8jzPFIv4DNACv+cuZoigNmjPLQ=",
|
|
||||||
"path": "github.com/technoweenie/multipartstreamer",
|
|
||||||
"revision": "a90a01d73ae432e2611d178c18367fbaa13e0154",
|
|
||||||
"revisionTime": "2013-10-20T00:18:33Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "E1efVncF6gxXUsd6vw4VgK4D+LI=",
|
|
||||||
"path": "github.com/urfave/cli",
|
|
||||||
"revision": "b892ba3809cd07fcf2b064e166b0c2e16e0147bd",
|
|
||||||
"revisionTime": "2017-06-25T03:28:08Z"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"checksumSHA1": "JaRjqSc0lOpA0V7avHWBex1IY+w=",
|
|
||||||
"path": "gopkg.in/telegram-bot-api.v4",
|
|
||||||
"revision": "2022d04b94f50056a09962b1ac81cdd821d20a55",
|
|
||||||
"revisionTime": "2017-11-09T18:51:50Z"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"rootPath": "github.com/appleboy/drone-telegram"
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user