├── .gitignore
├── LICENSE
├── README.md
├── _config.yml
├── cmd
├── inspect.go
├── root.go
└── server.go
├── draft.graphql
├── example.json
├── inspect
├── inspect.go
└── templates
│ └── schema.gotpl
├── main.go
├── server
└── server.go
├── utils
└── request.go
└── vendor
├── github.com
├── go-chi
│ ├── chi
│ │ ├── CHANGELOG.md
│ │ ├── CONTRIBUTING.md
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── chain.go
│ │ ├── chi.go
│ │ ├── context.go
│ │ ├── mux.go
│ │ └── tree.go
│ └── cors
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── cors.go
│ │ └── utils.go
└── urfave
│ └── cli
│ ├── CHANGELOG.md
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── LICENSE
│ ├── MAINTAINERS.md
│ ├── README.md
│ ├── app.go
│ ├── appveyor.yml
│ ├── category.go
│ ├── cli.go
│ ├── command.go
│ ├── context.go
│ ├── errors.go
│ ├── flag-types.json
│ ├── flag.go
│ ├── flag_generated.go
│ ├── funcs.go
│ ├── generate-flag-types
│ ├── help.go
│ ├── runtests
│ └── sort.go
└── vendor.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, build with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | .idea/*
15 | .idea
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | A script to generate graphql schema from json.
2 |
3 | # Usage
4 | ```bash
5 | go run main.go -h
6 | ```
7 |
8 |
9 | NAME:
10 | inspect - generate a graphql schema based on json
11 |
12 | USAGE:
13 | main [global options] command [command options] [arguments...]
14 |
15 | DESCRIPTION:
16 | inspect json and generate draft schema.graphql
17 |
18 | COMMANDS:
19 | inspect generate a graphql schema based on json
20 | help, h Shows a list of commands or help for one command
21 |
22 | GLOBAL OPTIONS:
23 | --verbose, -v show logs
24 | --input value, -i value the json filename
25 | --output value, -o value the target filename to store generated schema
26 | --help, -h show help
27 |
28 | # Example
29 |
30 | ```bash
31 | go run main.go -i example.json
32 | ```
33 |
34 | # TODO
35 |
36 | - [ ] build it as a web service that render schema on the fly like [json.cn](https://json.cn)
37 | - [ ] support to read from multi json files.
38 | - [ ] get input from http request rather than local file.
39 | - [ ] integrate with graphql server frameworks like [gqlgen](https://github.com/99designs/gqlgen) and auto generate resolver
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/cmd/inspect.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "github.com/luojilab/json2graphql/inspect"
8 | "github.com/urfave/cli"
9 | )
10 |
11 | var inspectCmd = cli.Command{
12 | Name: "inspect",
13 | Usage: "generate a graphql schema based on json",
14 | Flags: []cli.Flag{
15 | cli.BoolFlag{Name: "verbose, v", Usage: "Show logs"},
16 | cli.StringFlag{Name: "file, f", Usage: "The json filename, Cannot be used with -u "},
17 | cli.StringFlag{Name: "output, o", Usage: "The target filename to store generated schema, default is draft.graphql"},
18 | cli.StringFlag{Name: "url, u", Usage: "The json request url, Cannot be used with -u"},
19 | cli.StringFlag{Name: "token, t", Usage: "the token of json request url"},
20 | },
21 | Action: func(ctx *cli.Context) {
22 | var err error
23 |
24 | var output string
25 | if output = ctx.String("output"); output == "" {
26 | output = "draft.graphql"
27 | }
28 | if ctx.String("file") == "" && ctx.String("url") == "" {
29 | fmt.Println("param not found: -f or -i is needed.")
30 | os.Exit(2)
31 | } else if ctx.String("file") != "" && ctx.String("url") != "" {
32 | fmt.Println("param error: -f cannot be used with -u")
33 | os.Exit(2)
34 | } else if filename := ctx.String("file"); filename != "" {
35 | fmt.Println("schema create with json file")
36 | if err = inspect.InspectWithFile(filename, output); err != nil {
37 | os.Exit(2)
38 | }
39 | } else {
40 | url := ctx.String("url")
41 | token := ctx.String("token")
42 | if token == "" {
43 | fmt.Println("token is empty. you can input -f to request with token")
44 | }
45 | if err = inspect.InspectWithUrl(url, output, token); err != nil {
46 | os.Exit(2)
47 | }
48 | }
49 | },
50 | }
51 |
--------------------------------------------------------------------------------
/cmd/root.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "log"
7 | "os"
8 |
9 | "github.com/urfave/cli"
10 | )
11 |
12 | func Execute() {
13 | app := cli.NewApp()
14 | app.Name = "json2graphql"
15 | app.Usage = inspectCmd.Usage
16 | app.Description = "inspect json and generate draft schema.graphql"
17 | app.HideVersion = true
18 | app.Flags = inspectCmd.Flags
19 | app.Version = "0.0.2"
20 | app.Before = func(context *cli.Context) error {
21 | if context.Bool("verbose") {
22 | log.SetFlags(0)
23 | } else {
24 | log.SetOutput(ioutil.Discard)
25 | }
26 | return nil
27 | }
28 |
29 | app.Action = inspectCmd.Action
30 | app.Commands = []cli.Command{
31 | inspectCmd,
32 | serverCmd,
33 | }
34 |
35 | if err := app.Run(os.Args); err != nil {
36 | fmt.Fprintf(os.Stderr, err.Error())
37 | os.Exit(1)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/cmd/server.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/urfave/cli"
7 |
8 | "github.com/luojilab/json2graphql/server"
9 | )
10 |
11 | var serverCmd = cli.Command{
12 | Name: "server",
13 | Usage: "run a server that convert json to graphql schema",
14 | Flags: []cli.Flag{
15 | cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
16 | cli.StringFlag{Name: "port, p", Usage: "assign listening port(default is 8080)"},
17 | },
18 | Action: func(ctx *cli.Context) {
19 | var port string
20 | if port = ctx.String("port"); port == "" {
21 | port = ":8080"
22 | }
23 | fmt.Println("before")
24 | server.Run(port)
25 | fmt.Println("after")
26 | },
27 | }
28 |
--------------------------------------------------------------------------------
/draft.graphql:
--------------------------------------------------------------------------------
1 | # Code generated by github.com/luojilab.com/json2graphql
2 | # This is only draft of schema, please double check fields with TODO
3 |
4 |
5 | type Users {
6 | sex: String # TODO check this field
7 | id: Int
8 | name: String
9 | }
10 |
11 | type Extra {
12 | recheck_offset: String
13 | cache_key_order: String
14 | parent_platform: String
15 | cache_key_refund: String
16 | routing_key_order: String
17 | routing_key_refund: String
18 | page_size: String
19 | showcase_id: String
20 | }
21 |
22 | type Platform {
23 | created: String
24 | account: String
25 | key1: String
26 | site: String
27 | is_active: Boolean
28 | interval: String
29 | company: Int
30 | admin: Int
31 | id: Int
32 | updated: String
33 | account_ext: String
34 | api_url: String
35 | users: [Users]
36 | extra: Extra
37 | direction: Int
38 | display_name: String
39 | last_success: String # TODO check this field
40 | ptype: Int
41 | auth_valid: Boolean
42 | }
43 |
44 | type ExampleResult {
45 | platform: Platform
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "platform": {
3 | "id": 61,
4 | "created": "2018-06-26T18:19:13.701579+08:00",
5 | "updated": "2018-11-23T11:19:59.734070+08:00",
6 | "ptype": 3,
7 | "direction": 0,
8 | "account": "2",
9 | "account_ext": "",
10 | "display_name": "test shop",
11 | "key1": "77c3f00f1d40028",
12 | "site": "",
13 | "api_url": "http://image.example.com/",
14 | "auth_valid": true,
15 | "is_active": true,
16 | "interval": "00:05:00",
17 | "users": [
18 | {
19 | "id": 1,
20 | "name": "solo",
21 | "sex": null
22 | },
23 | {
24 | "id": 2,
25 | "name": "joe",
26 | "sex": "male"
27 | }
28 | ],
29 | "extra": {
30 | "page_size": "100",
31 | "showcase_id": "dev2_2",
32 | "recheck_offset": "1800",
33 | "cache_key_order": "10003_orders",
34 | "parent_platform": "4",
35 | "cache_key_refund": "2_refunds",
36 | "routing_key_order": "2.*.*",
37 | "routing_key_refund": "2.*"
38 | },
39 | "last_success": null,
40 | "company": 5,
41 | "admin": 9
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/inspect/inspect.go:
--------------------------------------------------------------------------------
1 | package inspect
2 |
3 | /* 解析 json, 提取类型并存入结构体
4 | 假定 json 文件最外层是大括号
5 | 先不处理有 list 的情况
6 | 文件名不支持中文
7 | */
8 | import (
9 | "bytes"
10 | "encoding/json"
11 | "fmt"
12 | "io/ioutil"
13 | "net/url"
14 | "os"
15 | "path/filepath"
16 | "reflect"
17 | "text/template"
18 | "unicode"
19 |
20 | "github.com/luojilab/json2graphql/utils"
21 | )
22 |
23 | func unmarshal(jsonRaw []byte) (interface{}, error) {
24 | var result interface{}
25 | var err error
26 |
27 | if err != nil {
28 | return nil, err
29 | }
30 | decoder := json.NewDecoder(bytes.NewReader(jsonRaw))
31 | decoder.UseNumber()
32 | err = decoder.Decode(&result)
33 |
34 | if err != nil {
35 | return nil, err
36 | }
37 | return result, nil
38 | }
39 |
40 | type Node struct {
41 | Name string
42 | ValueKind reflect.Kind
43 | ValueType reflect.Type
44 | InnerKind reflect.Kind /* 只有 ValueKind 为 Slice 时有值 */
45 | InnerType GqlType /* 只有 ValueKind 为 Slice 且 ValueKind 为 slice 时有值 */
46 | Children *[]Node
47 | }
48 |
49 | func (n *Node) RealType() string {
50 | var fieldMapping = map[reflect.Kind]string{
51 | reflect.Int: "Int",
52 | reflect.Float32: "Float",
53 | reflect.Float64: "Float64",
54 | reflect.String: "String",
55 | reflect.Bool: "Boolean",
56 | reflect.Map: "Map",
57 | reflect.Slice: "[]",
58 | reflect.Interface: "String # TODO check this field",
59 | }
60 | realType := fieldMapping[n.ValueKind]
61 | if realType == "Map" {
62 | realType = uppercaseFirst(n.Name)
63 | } else if realType == "[]" {
64 | if n.InnerKind == reflect.Map {
65 | realType = fmt.Sprintf("[%s]", n.InnerType.Name)
66 | } else {
67 | if n.InnerKind == reflect.Interface {
68 | // 处理空list 的注释问题
69 | realType = fmt.Sprintf("[String] # TODO check this field")
70 | } else {
71 | realType = fmt.Sprintf("[%s]", fieldMapping[n.InnerKind])
72 | }
73 | }
74 | } else if realType == "String" {
75 | if n.ValueType == reflect.TypeOf(123) {
76 | realType = "Int"
77 | } else if n.ValueType == reflect.TypeOf(123.4) {
78 | realType = "Float64"
79 | }
80 | }
81 | return realType
82 | }
83 |
84 | type GqlType struct {
85 | Name string
86 | Children *[]Node
87 | }
88 |
89 | func uppercaseFirst(s string) string {
90 | if s == "" {
91 | return ""
92 | }
93 |
94 | r := []rune(s)
95 | r[0] = unicode.ToUpper(r[0])
96 | return string(r)
97 | }
98 |
99 | func getRootType(s string) string {
100 | ext := filepath.Ext(s)
101 | return uppercaseFirst(s[0 : len(s)-len(ext)])
102 | }
103 |
104 | func ensureAndAppend(ptr *[]Node, node Node) *[]Node {
105 | if ptr == nil {
106 | arr := make([]Node, 0)
107 | ptr = &arr
108 | }
109 | *ptr = append(*ptr, node)
110 | return ptr
111 | }
112 |
113 | func guessIntOrFloat(value interface{}) reflect.Type {
114 | numberValue := value.(json.Number)
115 | var guessedType reflect.Type
116 | guessedType = reflect.TypeOf("str")
117 | _, err := numberValue.Int64()
118 | if err == nil {
119 | guessedType = reflect.TypeOf(123)
120 | } else {
121 | _, err = numberValue.Float64()
122 | if err == nil {
123 | guessedType = reflect.TypeOf(123.4)
124 | }
125 | }
126 | return guessedType
127 |
128 | }
129 |
130 | func parseList(obj interface{}, gqlTypesPtr *[]GqlType, gqlType GqlType, node Node) {
131 | // 解析 list 类型
132 | fmt.Printf("node.Name %v\n", node.Name)
133 | innterList := obj.([]interface{})
134 | if len(innterList) == 0 || innterList == nil {
135 | node.InnerKind = reflect.Interface
136 | } else {
137 | // 如果列表不为空,取第一个元素列表判断内部元素类型
138 | firstItem := innterList[0]
139 | itemKind := reflect.TypeOf(firstItem).Kind()
140 |
141 | node.InnerKind = itemKind
142 | // map 或简单类型 或 list ?
143 | if itemKind == reflect.Map {
144 | // item 的 type 加入 types
145 | innerGqlType := GqlType{Name: uppercaseFirst(node.Name)}
146 | Parse(firstItem, gqlTypesPtr, innerGqlType, node)
147 | node.InnerType = innerGqlType
148 | }
149 | }
150 | *gqlTypesPtr = append(*gqlTypesPtr, gqlType)
151 | }
152 |
153 | func Parse(obj interface{}, gqlTypesPtr *[]GqlType, gqlType GqlType, node Node) {
154 |
155 | numberType := reflect.TypeOf(json.Number(""))
156 |
157 | for key, value := range obj.(map[string]interface{}) {
158 |
159 | var valueKind reflect.Kind
160 | if value == nil {
161 | valueKind = reflect.Interface
162 | } else {
163 | valueKind = reflect.TypeOf(value).Kind()
164 | }
165 |
166 | child := Node{Name: key, ValueKind: valueKind}
167 |
168 | if reflect.TypeOf(value) == numberType {
169 | child.ValueType = guessIntOrFloat(value)
170 | }
171 |
172 | if value != nil && valueKind == reflect.Map {
173 |
174 | childGqlType := GqlType{Name: uppercaseFirst(key)}
175 | Parse(value, gqlTypesPtr, childGqlType, child)
176 |
177 | } else if valueKind == reflect.Slice {
178 | // 解析 list 类型
179 | innterList := value.([]interface{})
180 | if len(innterList) == 0 || innterList == nil {
181 | child.InnerKind = reflect.Interface
182 |
183 | } else {
184 | // 如果列表不为空,取第一个元素列表判断内部元素类型
185 | firstItem := innterList[0]
186 | itemKind := reflect.TypeOf(firstItem).Kind()
187 |
188 | child.InnerKind = itemKind
189 | // map 或简单类型 或 list ?
190 | if itemKind == reflect.Map {
191 | // item 的 type 加入 types
192 | childGqlType := GqlType{Name: uppercaseFirst(key)}
193 | Parse(firstItem, gqlTypesPtr, childGqlType, child)
194 | child.InnerType = childGqlType
195 | }
196 | }
197 | }
198 | // 为父类型添加子类型
199 | gqlType.Children = ensureAndAppend(gqlType.Children, child)
200 |
201 | // 为父节点添加当前节点
202 | node.Children = ensureAndAppend(node.Children, child)
203 | }
204 | *gqlTypesPtr = append(*gqlTypesPtr, gqlType)
205 | }
206 |
207 | func GenerateSchema(gqlTypes []GqlType, tmpl string, output string) error {
208 | tname := filepath.Base(tmpl)
209 | f, err := os.Create(output)
210 | if err != nil {
211 | fmt.Println("create file: ", err)
212 | return err
213 | }
214 |
215 | defer f.Close()
216 | t := template.Must(template.New(tname).Funcs(template.FuncMap{
217 |
218 | "Deref": func(children *[]Node) []Node {
219 | if children != nil {
220 | return *children
221 | } else {
222 | return nil
223 | }
224 | },
225 | }).ParseFiles(tmpl))
226 |
227 | m := map[string]interface{}{"gqlTypes": gqlTypes}
228 | err = t.ExecuteTemplate(f, tname, m)
229 | if err != nil {
230 | fmt.Println(err)
231 | return err
232 | }
233 | return nil
234 |
235 | }
236 |
237 | func GenerateSchema2Byte(gqlTypes []GqlType, tmpl string) ([]byte, error) {
238 | var buf bytes.Buffer
239 | // writer := bufio.NewWriter(&buf)
240 | tname := filepath.Base(tmpl)
241 | t := template.Must(template.New(tname).Funcs(template.FuncMap{
242 |
243 | "Deref": func(children *[]Node) []Node {
244 | if children != nil {
245 | return *children
246 | } else {
247 | return nil
248 | }
249 | },
250 | }).ParseFiles(tmpl))
251 |
252 | m := map[string]interface{}{"gqlTypes": gqlTypes}
253 | err := t.ExecuteTemplate(&buf, tname, m)
254 | if err != nil {
255 | fmt.Println(err)
256 | return nil, err
257 | }
258 | return buf.Bytes(), nil
259 | }
260 |
261 | func inspect(input []byte, output string, name string) error {
262 | // TODO 支持多个文件
263 | tmpl := "inspect/templates/schema.gotpl"
264 | rootObj, err := unmarshal(input)
265 |
266 | if err != nil {
267 | fmt.Printf("error: %v", err.Error())
268 | return err
269 | }
270 |
271 | t := reflect.TypeOf(rootObj).Kind()
272 |
273 | mapKind := reflect.Map
274 |
275 | root := Node{Name: "root", ValueKind: t}
276 | rootType := GqlType{Name: name + "Result"}
277 | gqlTypes := make([]GqlType, 0)
278 | gqlTypesPtr := &gqlTypes
279 | if t == mapKind {
280 | Parse(rootObj, gqlTypesPtr, rootType, root)
281 | err = GenerateSchema(gqlTypes, tmpl, output)
282 | if err != nil {
283 | fmt.Printf("error: %v", err.Error())
284 | return err
285 | }
286 |
287 | } else {
288 | // TODO 顶层为 list
289 | panic("not supported root type")
290 | }
291 | return nil
292 | }
293 |
294 | func inspect2Bytes(input []byte, name string) ([]byte, error) {
295 | // TODO 支持多个文件
296 | tmpl := "inspect/templates/schema.gotpl"
297 | rootObj, err := unmarshal(input)
298 | fmt.Printf("root obj is %v\n", rootObj)
299 | var result []byte
300 |
301 | if err != nil {
302 | fmt.Printf("error: %v", err.Error())
303 | return nil, err
304 | }
305 |
306 | t := reflect.TypeOf(rootObj).Kind()
307 |
308 | mapKind := reflect.Map
309 |
310 | root := Node{Name: "root", ValueKind: t}
311 | rootType := GqlType{Name: name + "Result"}
312 | gqlTypes := make([]GqlType, 0)
313 | gqlTypesPtr := &gqlTypes
314 | if t == mapKind {
315 | Parse(rootObj, gqlTypesPtr, rootType, root)
316 | result, err = GenerateSchema2Byte(gqlTypes, tmpl)
317 | if err != nil {
318 | fmt.Printf("error: %v\n", err.Error())
319 | return nil, err
320 | }
321 |
322 | } else {
323 | // TODO 顶层为 list
324 | panic("not supported root type")
325 | }
326 | return result, nil
327 | }
328 |
329 | func InspectWithFile(filename, output string) error {
330 | input, err := ioutil.ReadFile(filename)
331 | if err != nil {
332 | fmt.Println(err)
333 | return err
334 | }
335 | name := getRootType(filename)
336 | if err := inspect(input, output, name); err != nil {
337 | fmt.Printf("error")
338 | return err
339 | }
340 | return nil
341 | }
342 |
343 | func InspectWithUrl(requestUrl, output, token string) error {
344 | // TODO 支持传入参数进行请求
345 | var params url.Values
346 | if input, code, err := utils.HttpGet(requestUrl, params, token); err != nil {
347 | fmt.Printf("error of %s", err)
348 | return err
349 | } else if code != 200 {
350 | fmt.Printf("request error of status code: %d", code)
351 | return nil
352 | } else {
353 | name := getRootType(output)
354 | if err := inspect(input, output, name); err != nil {
355 | return err
356 | }
357 | }
358 | return nil
359 | }
360 |
361 | func InspectWithBytes(input []byte) ([]byte, error) {
362 | name := "Root"
363 | var err error
364 | var result []byte
365 | result, err = inspect2Bytes(input, name)
366 | if err != nil {
367 | fmt.Println(err)
368 | return nil, err
369 | }
370 | return result, nil
371 | }
372 |
--------------------------------------------------------------------------------
/inspect/templates/schema.gotpl:
--------------------------------------------------------------------------------
1 | # Code generated by github.com/luojilab.com/json2graphql
2 | # This is only draft of schema, please double check fields with TODO
3 |
4 | {{ range $gqlType := .gqlTypes }}
5 | type {{ $gqlType.Name }} {
6 | {{- range $field := (Deref $gqlType.Children) }}
7 | {{ $field.Name }}: {{ $field.RealType }}
8 | {{- end }}
9 | }
10 | {{ end }}
11 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/luojilab/json2graphql/cmd"
4 |
5 | func main() {
6 | cmd.Execute()
7 | }
8 |
--------------------------------------------------------------------------------
/server/server.go:
--------------------------------------------------------------------------------
1 | package server
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "net/http"
7 |
8 | "github.com/go-chi/chi"
9 | "github.com/go-chi/cors"
10 | "github.com/luojilab/json2graphql/inspect"
11 | )
12 |
13 | func Run(port string) {
14 | router := chi.NewRouter()
15 | cors := cors.New(cors.Options{
16 | AllowedOrigins: []string{"*"},
17 | AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
18 | AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
19 | ExposedHeaders: []string{"Link"},
20 | AllowCredentials: true,
21 | MaxAge: 300, // Maximum value not ignored by any of major browsers
22 | })
23 | router.Use(cors.Handler)
24 |
25 | router.Post("/inspect/", Inspect)
26 | fmt.Printf("start listening on port is %s\n", port)
27 | err := http.ListenAndServe(port, router)
28 | if err != nil {
29 | fmt.Println(err)
30 | panic(err)
31 | }
32 | }
33 |
34 | func Inspect(w http.ResponseWriter, r *http.Request) {
35 | body, err := ioutil.ReadAll(r.Body)
36 | if err != nil {
37 | fmt.Println(err)
38 | w.Write([]byte(fmt.Sprintf("%v", err)))
39 | }
40 | output, err := inspect.InspectWithBytes(body)
41 | fmt.Printf("body is\n %v\n", string(body))
42 | fmt.Printf("return is \n%v\n", string(output))
43 | if err != nil {
44 | fmt.Println(err)
45 | w.Write([]byte(fmt.Sprintf("%v", err)))
46 | } else {
47 | w.Write(output)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/utils/request.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "io/ioutil"
7 | "net/http"
8 | "net/url"
9 | )
10 |
11 | func HttpGet(getUrl string, params url.Values, token string) ([]byte, int, error) {
12 | u, _ := url.Parse(getUrl)
13 | u.RawQuery = params.Encode()
14 | data, code, err := httpDo("GET", u.String(), []byte(""), token)
15 | if err != nil {
16 | return nil, code, err
17 | }
18 | return data, code, nil
19 | }
20 |
21 | func HttpPost(postUrl string, body []byte, token string) ([]byte, int, error) {
22 | u, _ := url.Parse(postUrl)
23 | data, code, err := httpDo("POST", u.String(), body, token)
24 | if err != nil {
25 | return nil, code, err
26 | }
27 | return data, code, nil
28 | }
29 |
30 | func httpDo(methodType string, url string, body []byte, token string) ([]byte, int, error) {
31 | fmt.Println(url)
32 | if methodType == "" {
33 | methodType = "GET"
34 | }
35 |
36 | client := &http.Client{}
37 | req, err := http.NewRequest(methodType, url, bytes.NewReader(body))
38 | if err != nil {
39 | return nil, 500, err
40 | }
41 | req.Header.Set("Content-Type", "application/json")
42 | req.Header.Set("Authorization", token)
43 |
44 | resp, err := client.Do(req)
45 |
46 | defer resp.Body.Close()
47 |
48 | data, err := ioutil.ReadAll(resp.Body)
49 | if err != nil {
50 | return nil, resp.StatusCode, err
51 | }
52 | return data, resp.StatusCode, nil
53 | }
54 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## v4.0.0 (2019-01-10)
4 |
5 | - chi v4 requires Go 1.10.3+ (or Go 1.9.7+) - we have deprecated support for Go 1.7 and 1.8
6 | - router: respond with 404 on router with no routes (#362)
7 | - router: additional check to ensure wildcard is at the end of a url pattern (#333)
8 | - middleware: deprecate use of http.CloseNotifier (#347)
9 | - middleware: fix RedirectSlashes to include query params on redirect (#334)
10 | - History of changes: see https://github.com/go-chi/chi/compare/v3.3.4...v4.0.0
11 |
12 |
13 | ## v3.3.4 (2019-01-07)
14 |
15 | - Minor middleware improvements. No changes to core library/router. Moving v3 into its
16 | - own branch as a version of chi for Go 1.7, 1.8, 1.9, 1.10, 1.11
17 | - History of changes: see https://github.com/go-chi/chi/compare/v3.3.3...v3.3.4
18 |
19 |
20 | ## v3.3.3 (2018-08-27)
21 |
22 | - Minor release
23 | - See https://github.com/go-chi/chi/compare/v3.3.2...v3.3.3
24 |
25 |
26 | ## v3.3.2 (2017-12-22)
27 |
28 | - Support to route trailing slashes on mounted sub-routers (#281)
29 | - middleware: new `ContentCharset` to check matching charsets. Thank you
30 | @csucu for your community contribution!
31 |
32 |
33 | ## v3.3.1 (2017-11-20)
34 |
35 | - middleware: new `AllowContentType` handler for explicit whitelist of accepted request Content-Types
36 | - middleware: new `SetHeader` handler for short-hand middleware to set a response header key/value
37 | - Minor bug fixes
38 |
39 |
40 | ## v3.3.0 (2017-10-10)
41 |
42 | - New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage
43 | - Deprecated LINK and UNLINK methods from the default list, please use `chi.RegisterMethod("LINK")` and `chi.RegisterMethod("UNLINK")` in an `init()` function
44 |
45 |
46 | ## v3.2.1 (2017-08-31)
47 |
48 | - Add new `Match(rctx *Context, method, path string) bool` method to `Routes` interface
49 | and `Mux`. Match searches the mux's routing tree for a handler that matches the method/path
50 | - Add new `RouteMethod` to `*Context`
51 | - Add new `Routes` pointer to `*Context`
52 | - Add new `middleware.GetHead` to route missing HEAD requests to GET handler
53 | - Updated benchmarks (see README)
54 |
55 |
56 | ## v3.1.5 (2017-08-02)
57 |
58 | - Setup golint and go vet for the project
59 | - As per golint, we've redefined `func ServerBaseContext(h http.Handler, baseCtx context.Context) http.Handler`
60 | to `func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler`
61 |
62 |
63 | ## v3.1.0 (2017-07-10)
64 |
65 | - Fix a few minor issues after v3 release
66 | - Move `docgen` sub-pkg to https://github.com/go-chi/docgen
67 | - Move `render` sub-pkg to https://github.com/go-chi/render
68 | - Add new `URLFormat` handler to chi/middleware sub-pkg to make working with url mime
69 | suffixes easier, ie. parsing `/articles/1.json` and `/articles/1.xml`. See comments in
70 | https://github.com/go-chi/chi/blob/master/middleware/url_format.go for example usage.
71 |
72 |
73 | ## v3.0.0 (2017-06-21)
74 |
75 | - Major update to chi library with many exciting updates, but also some *breaking changes*
76 | - URL parameter syntax changed from `/:id` to `/{id}` for even more flexible routing, such as
77 | `/articles/{month}-{day}-{year}-{slug}`, `/articles/{id}`, and `/articles/{id}.{ext}` on the
78 | same router
79 | - Support for regexp for routing patterns, in the form of `/{paramKey:regExp}` for example:
80 | `r.Get("/articles/{name:[a-z]+}", h)` and `chi.URLParam(r, "name")`
81 | - Add `Method` and `MethodFunc` to `chi.Router` to allow routing definitions such as
82 | `r.Method("GET", "/", h)` which provides a cleaner interface for custom handlers like
83 | in `_examples/custom-handler`
84 | - Deprecating `mux#FileServer` helper function. Instead, we encourage users to create their
85 | own using file handler with the stdlib, see `_examples/fileserver` for an example
86 | - Add support for LINK/UNLINK http methods via `r.Method()` and `r.MethodFunc()`
87 | - Moved the chi project to its own organization, to allow chi-related community packages to
88 | be easily discovered and supported, at: https://github.com/go-chi
89 | - *NOTE:* please update your import paths to `"github.com/go-chi/chi"`
90 | - *NOTE:* chi v2 is still available at https://github.com/go-chi/chi/tree/v2
91 |
92 |
93 | ## v2.1.0 (2017-03-30)
94 |
95 | - Minor improvements and update to the chi core library
96 | - Introduced a brand new `chi/render` sub-package to complete the story of building
97 | APIs to offer a pattern for managing well-defined request / response payloads. Please
98 | check out the updated `_examples/rest` example for how it works.
99 | - Added `MethodNotAllowed(h http.HandlerFunc)` to chi.Router interface
100 |
101 |
102 | ## v2.0.0 (2017-01-06)
103 |
104 | - After many months of v2 being in an RC state with many companies and users running it in
105 | production, the inclusion of some improvements to the middlewares, we are very pleased to
106 | announce v2.0.0 of chi.
107 |
108 |
109 | ## v2.0.0-rc1 (2016-07-26)
110 |
111 | - Huge update! chi v2 is a large refactor targetting Go 1.7+. As of Go 1.7, the popular
112 | community `"net/context"` package has been included in the standard library as `"context"` and
113 | utilized by `"net/http"` and `http.Request` to managing deadlines, cancelation signals and other
114 | request-scoped values. We're very excited about the new context addition and are proud to
115 | introduce chi v2, a minimal and powerful routing package for building large HTTP services,
116 | with zero external dependencies. Chi focuses on idiomatic design and encourages the use of
117 | stdlib HTTP handlers and middlwares.
118 | - chi v2 deprecates its `chi.Handler` interface and requires `http.Handler` or `http.HandlerFunc`
119 | - chi v2 stores URL routing parameters and patterns in the standard request context: `r.Context()`
120 | - chi v2 lower-level routing context is accessible by `chi.RouteContext(r.Context()) *chi.Context`,
121 | which provides direct access to URL routing parameters, the routing path and the matching
122 | routing patterns.
123 | - Users upgrading from chi v1 to v2, need to:
124 | 1. Update the old chi.Handler signature, `func(ctx context.Context, w http.ResponseWriter, r *http.Request)` to
125 | the standard http.Handler: `func(w http.ResponseWriter, r *http.Request)`
126 | 2. Use `chi.URLParam(r *http.Request, paramKey string) string`
127 | or `URLParamFromCtx(ctx context.Context, paramKey string) string` to access a url parameter value
128 |
129 |
130 | ## v1.0.0 (2016-07-01)
131 |
132 | - Released chi v1 stable https://github.com/go-chi/chi/tree/v1.0.0 for Go 1.6 and older.
133 |
134 |
135 | ## v0.9.0 (2016-03-31)
136 |
137 | - Reuse context objects via sync.Pool for zero-allocation routing [#33](https://github.com/go-chi/chi/pull/33)
138 | - BREAKING NOTE: due to subtle API changes, previously `chi.URLParams(ctx)["id"]` used to access url parameters
139 | has changed to: `chi.URLParam(ctx, "id")`
140 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Prerequisites
4 |
5 | 1. [Install Go][go-install].
6 | 2. Download the sources and switch the working directory:
7 |
8 | ```bash
9 | go get -u -d github.com/go-chi/chi
10 | cd $GOPATH/src/github.com/go-chi/chi
11 | ```
12 |
13 | ## Submitting a Pull Request
14 |
15 | A typical workflow is:
16 |
17 | 1. [Fork the repository.][fork] [This tip maybe also helpful.][go-fork-tip]
18 | 2. [Create a topic branch.][branch]
19 | 3. Add tests for your change.
20 | 4. Run `go test`. If your tests pass, return to the step 3.
21 | 5. Implement the change and ensure the steps from the previous step pass.
22 | 6. Run `goimports -w .`, to ensure the new code conforms to Go formatting guideline.
23 | 7. [Add, commit and push your changes.][git-help]
24 | 8. [Submit a pull request.][pull-req]
25 |
26 | [go-install]: https://golang.org/doc/install
27 | [go-fork-tip]: http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html
28 | [fork]: https://help.github.com/articles/fork-a-repo
29 | [branch]: http://learn.github.com/p/branching.html
30 | [git-help]: https://guides.github.com
31 | [pull-req]: https://help.github.com/articles/using-pull-requests
32 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc.
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/README.md:
--------------------------------------------------------------------------------
1 | #
2 |
3 |
4 | [![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis]
5 |
6 | `chi` is a lightweight, idiomatic and composable router for building Go HTTP services. It's
7 | especially good at helping you write large REST API services that are kept maintainable as your
8 | project grows and changes. `chi` is built on the new `context` package introduced in Go 1.7 to
9 | handle signaling, cancelation and request-scoped values across a handler chain.
10 |
11 | The focus of the project has been to seek out an elegant and comfortable design for writing
12 | REST API servers, written during the development of the Pressly API service that powers our
13 | public API service, which in turn powers all of our client-side applications.
14 |
15 | The key considerations of chi's design are: project structure, maintainability, standard http
16 | handlers (stdlib-only), developer productivity, and deconstructing a large system into many small
17 | parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also
18 | included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render) and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too!
19 |
20 | ## Install
21 |
22 | `go get -u github.com/go-chi/chi`
23 |
24 |
25 | ## Features
26 |
27 | * **Lightweight** - cloc'd in ~1000 LOC for the chi router
28 | * **Fast** - yes, see [benchmarks](#benchmarks)
29 | * **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http`
30 | * **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and subrouter mounting
31 | * **Context control** - built on new `context` package, providing value chaining, cancelations and timeouts
32 | * **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91))
33 | * **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown
34 | * **No external dependencies** - plain ol' Go stdlib + net/http
35 |
36 |
37 | ## Examples
38 |
39 | See [_examples/](https://github.com/go-chi/chi/blob/master/_examples/) for a variety of examples.
40 |
41 |
42 | **As easy as:**
43 |
44 | ```go
45 | package main
46 |
47 | import (
48 | "net/http"
49 | "github.com/go-chi/chi"
50 | )
51 |
52 | func main() {
53 | r := chi.NewRouter()
54 | r.Get("/", func(w http.ResponseWriter, r *http.Request) {
55 | w.Write([]byte("welcome"))
56 | })
57 | http.ListenAndServe(":3000", r)
58 | }
59 | ```
60 |
61 | **REST Preview:**
62 |
63 | Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs
64 | in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in
65 | Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)).
66 |
67 | I highly recommend reading the source of the [examples](https://github.com/go-chi/chi/blob/master/_examples/) listed
68 | above, they will show you all the features of chi and serve as a good form of documentation.
69 |
70 | ```go
71 | import (
72 | //...
73 | "context"
74 | "github.com/go-chi/chi"
75 | "github.com/go-chi/chi/middleware"
76 | )
77 |
78 | func main() {
79 | r := chi.NewRouter()
80 |
81 | // A good base middleware stack
82 | r.Use(middleware.RequestID)
83 | r.Use(middleware.RealIP)
84 | r.Use(middleware.Logger)
85 | r.Use(middleware.Recoverer)
86 |
87 | // Set a timeout value on the request context (ctx), that will signal
88 | // through ctx.Done() that the request has timed out and further
89 | // processing should be stopped.
90 | r.Use(middleware.Timeout(60 * time.Second))
91 |
92 | r.Get("/", func(w http.ResponseWriter, r *http.Request) {
93 | w.Write([]byte("hi"))
94 | })
95 |
96 | // RESTy routes for "articles" resource
97 | r.Route("/articles", func(r chi.Router) {
98 | r.With(paginate).Get("/", listArticles) // GET /articles
99 | r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017
100 |
101 | r.Post("/", createArticle) // POST /articles
102 | r.Get("/search", searchArticles) // GET /articles/search
103 |
104 | // Regexp url parameters:
105 | r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto
106 |
107 | // Subrouters:
108 | r.Route("/{articleID}", func(r chi.Router) {
109 | r.Use(ArticleCtx)
110 | r.Get("/", getArticle) // GET /articles/123
111 | r.Put("/", updateArticle) // PUT /articles/123
112 | r.Delete("/", deleteArticle) // DELETE /articles/123
113 | })
114 | })
115 |
116 | // Mount the admin sub-router
117 | r.Mount("/admin", adminRouter())
118 |
119 | http.ListenAndServe(":3333", r)
120 | }
121 |
122 | func ArticleCtx(next http.Handler) http.Handler {
123 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
124 | articleID := chi.URLParam(r, "articleID")
125 | article, err := dbGetArticle(articleID)
126 | if err != nil {
127 | http.Error(w, http.StatusText(404), 404)
128 | return
129 | }
130 | ctx := context.WithValue(r.Context(), "article", article)
131 | next.ServeHTTP(w, r.WithContext(ctx))
132 | })
133 | }
134 |
135 | func getArticle(w http.ResponseWriter, r *http.Request) {
136 | ctx := r.Context()
137 | article, ok := ctx.Value("article").(*Article)
138 | if !ok {
139 | http.Error(w, http.StatusText(422), 422)
140 | return
141 | }
142 | w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
143 | }
144 |
145 | // A completely separate router for administrator routes
146 | func adminRouter() http.Handler {
147 | r := chi.NewRouter()
148 | r.Use(AdminOnly)
149 | r.Get("/", adminIndex)
150 | r.Get("/accounts", adminListAccounts)
151 | return r
152 | }
153 |
154 | func AdminOnly(next http.Handler) http.Handler {
155 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
156 | ctx := r.Context()
157 | perm, ok := ctx.Value("acl.permission").(YourPermissionType)
158 | if !ok || !perm.IsAdmin() {
159 | http.Error(w, http.StatusText(403), 403)
160 | return
161 | }
162 | next.ServeHTTP(w, r)
163 | })
164 | }
165 | ```
166 |
167 |
168 | ## Router design
169 |
170 | chi's router is based on a kind of [Patricia Radix trie](https://en.wikipedia.org/wiki/Radix_tree).
171 | The router is fully compatible with `net/http`.
172 |
173 | Built on top of the tree is the `Router` interface:
174 |
175 | ```go
176 | // Router consisting of the core routing methods used by chi's Mux,
177 | // using only the standard net/http.
178 | type Router interface {
179 | http.Handler
180 | Routes
181 |
182 | // Use appends one of more middlewares onto the Router stack.
183 | Use(middlewares ...func(http.Handler) http.Handler)
184 |
185 | // With adds inline middlewares for an endpoint handler.
186 | With(middlewares ...func(http.Handler) http.Handler) Router
187 |
188 | // Group adds a new inline-Router along the current routing
189 | // path, with a fresh middleware stack for the inline-Router.
190 | Group(fn func(r Router)) Router
191 |
192 | // Route mounts a sub-Router along a `pattern`` string.
193 | Route(pattern string, fn func(r Router)) Router
194 |
195 | // Mount attaches another http.Handler along ./pattern/*
196 | Mount(pattern string, h http.Handler)
197 |
198 | // Handle and HandleFunc adds routes for `pattern` that matches
199 | // all HTTP methods.
200 | Handle(pattern string, h http.Handler)
201 | HandleFunc(pattern string, h http.HandlerFunc)
202 |
203 | // Method and MethodFunc adds routes for `pattern` that matches
204 | // the `method` HTTP method.
205 | Method(method, pattern string, h http.Handler)
206 | MethodFunc(method, pattern string, h http.HandlerFunc)
207 |
208 | // HTTP-method routing along `pattern`
209 | Connect(pattern string, h http.HandlerFunc)
210 | Delete(pattern string, h http.HandlerFunc)
211 | Get(pattern string, h http.HandlerFunc)
212 | Head(pattern string, h http.HandlerFunc)
213 | Options(pattern string, h http.HandlerFunc)
214 | Patch(pattern string, h http.HandlerFunc)
215 | Post(pattern string, h http.HandlerFunc)
216 | Put(pattern string, h http.HandlerFunc)
217 | Trace(pattern string, h http.HandlerFunc)
218 |
219 | // NotFound defines a handler to respond whenever a route could
220 | // not be found.
221 | NotFound(h http.HandlerFunc)
222 |
223 | // MethodNotAllowed defines a handler to respond whenever a method is
224 | // not allowed.
225 | MethodNotAllowed(h http.HandlerFunc)
226 | }
227 |
228 | // Routes interface adds two methods for router traversal, which is also
229 | // used by the github.com/go-chi/docgen package to generate documentation for Routers.
230 | type Routes interface {
231 | // Routes returns the routing tree in an easily traversable structure.
232 | Routes() []Route
233 |
234 | // Middlewares returns the list of middlewares in use by the router.
235 | Middlewares() Middlewares
236 |
237 | // Match searches the routing tree for a handler that matches
238 | // the method/path - similar to routing a http request, but without
239 | // executing the handler thereafter.
240 | Match(rctx *Context, method, path string) bool
241 | }
242 | ```
243 |
244 | Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern
245 | supports named params (ie. `/users/{userID}`) and wildcards (ie. `/admin/*`). URL parameters
246 | can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters
247 | and `chi.URLParam(r, "*")` for a wildcard parameter.
248 |
249 |
250 | ### Middleware handlers
251 |
252 | chi's middlewares are just stdlib net/http middleware handlers. There is nothing special
253 | about them, which means the router and all the tooling is designed to be compatible and
254 | friendly with any middleware in the community. This offers much better extensibility and reuse
255 | of packages and is at the heart of chi's purpose.
256 |
257 | Here is an example of a standard net/http middleware handler using the new request context
258 | available in Go. This middleware sets a hypothetical user identifier on the request
259 | context and calls the next handler in the chain.
260 |
261 | ```go
262 | // HTTP middleware setting a value on the request context
263 | func MyMiddleware(next http.Handler) http.Handler {
264 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
265 | ctx := context.WithValue(r.Context(), "user", "123")
266 | next.ServeHTTP(w, r.WithContext(ctx))
267 | })
268 | }
269 | ```
270 |
271 |
272 | ### Request handlers
273 |
274 | chi uses standard net/http request handlers. This little snippet is an example of a http.Handler
275 | func that reads a user identifier from the request context - hypothetically, identifying
276 | the user sending an authenticated request, validated+set by a previous middleware handler.
277 |
278 | ```go
279 | // HTTP handler accessing data from the request context.
280 | func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
281 | user := r.Context().Value("user").(string)
282 | w.Write([]byte(fmt.Sprintf("hi %s", user)))
283 | }
284 | ```
285 |
286 |
287 | ### URL parameters
288 |
289 | chi's router parses and stores URL parameters right onto the request context. Here is
290 | an example of how to access URL params in your net/http handlers. And of course, middlewares
291 | are able to access the same information.
292 |
293 | ```go
294 | // HTTP handler accessing the url routing parameters.
295 | func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
296 | userID := chi.URLParam(r, "userID") // from a route like /users/{userID}
297 |
298 | ctx := r.Context()
299 | key := ctx.Value("key").(string)
300 |
301 | w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key)))
302 | }
303 | ```
304 |
305 |
306 | ## Middlewares
307 |
308 | chi comes equipped with an optional `middleware` package, providing a suite of standard
309 | `net/http` middlewares. Please note, any middleware in the ecosystem that is also compatible
310 | with `net/http` can be used with chi's mux.
311 |
312 | ### Core middlewares
313 |
314 | -----------------------------------------------------------------------------------------------------------
315 | | chi/middleware Handler | description |
316 | |:----------------------|:---------------------------------------------------------------------------------
317 | | AllowContentType | Explicit whitelist of accepted request Content-Types |
318 | | Compress | Gzip compression for clients that accept compressed responses |
319 | | GetHead | Automatically route undefined HEAD requests to GET handlers |
320 | | Heartbeat | Monitoring endpoint to check the servers pulse |
321 | | Logger | Logs the start and end of each request with the elapsed processing time |
322 | | NoCache | Sets response headers to prevent clients from caching |
323 | | Profiler | Easily attach net/http/pprof to your routers |
324 | | RealIP | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP |
325 | | Recoverer | Gracefully absorb panics and prints the stack trace |
326 | | RequestID | Injects a request ID into the context of each request |
327 | | RedirectSlashes | Redirect slashes on routing paths |
328 | | SetHeader | Short-hand middleware to set a response header key/value |
329 | | StripSlashes | Strip slashes on routing paths |
330 | | Throttle | Puts a ceiling on the number of concurrent requests |
331 | | Timeout | Signals to the request context when the timeout deadline is reached |
332 | | URLFormat | Parse extension from url and put it on request context |
333 | | WithValue | Short-hand middleware to set a key/value on the request context |
334 | -----------------------------------------------------------------------------------------------------------
335 |
336 | ### Auxiliary middlewares & packages
337 |
338 | Please see https://github.com/go-chi for additional packages.
339 |
340 | --------------------------------------------------------------------------------------------------------------------
341 | | package | description |
342 | |:---------------------------------------------------|:-------------------------------------------------------------
343 | | [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) |
344 | | [docgen](https://github.com/go-chi/docgen) | Print chi.Router routes at runtime |
345 | | [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication |
346 | | [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing |
347 | | [httpcoala](https://github.com/go-chi/httpcoala) | HTTP request coalescer |
348 | | [chi-authz](https://github.com/casbin/chi-authz) | Request ACL via https://github.com/hsluoyz/casbin |
349 | | [phi](https://github.com/fate-lovely/phi) | Port chi to [fasthttp](https://github.com/valyala/fasthttp) |
350 | --------------------------------------------------------------------------------------------------------------------
351 |
352 | please [submit a PR](./CONTRIBUTING.md) if you'd like to include a link to a chi-compatible middleware
353 |
354 |
355 | ## context?
356 |
357 | `context` is a tiny pkg that provides simple interface to signal context across call stacks
358 | and goroutines. It was originally written by [Sameer Ajmani](https://github.com/Sajmani)
359 | and is available in stdlib since go1.7.
360 |
361 | Learn more at https://blog.golang.org/context
362 |
363 | and..
364 | * Docs: https://golang.org/pkg/context
365 | * Source: https://github.com/golang/go/tree/master/src/context
366 |
367 |
368 | ## Benchmarks
369 |
370 | The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark
371 |
372 | Results as of Jan 9, 2019 with Go 1.11.4 on Linux X1 Carbon laptop
373 |
374 | ```shell
375 | BenchmarkChi_Param 3000000 475 ns/op 432 B/op 3 allocs/op
376 | BenchmarkChi_Param5 2000000 696 ns/op 432 B/op 3 allocs/op
377 | BenchmarkChi_Param20 1000000 1275 ns/op 432 B/op 3 allocs/op
378 | BenchmarkChi_ParamWrite 3000000 505 ns/op 432 B/op 3 allocs/op
379 | BenchmarkChi_GithubStatic 3000000 508 ns/op 432 B/op 3 allocs/op
380 | BenchmarkChi_GithubParam 2000000 669 ns/op 432 B/op 3 allocs/op
381 | BenchmarkChi_GithubAll 10000 134627 ns/op 87699 B/op 609 allocs/op
382 | BenchmarkChi_GPlusStatic 3000000 402 ns/op 432 B/op 3 allocs/op
383 | BenchmarkChi_GPlusParam 3000000 500 ns/op 432 B/op 3 allocs/op
384 | BenchmarkChi_GPlus2Params 3000000 586 ns/op 432 B/op 3 allocs/op
385 | BenchmarkChi_GPlusAll 200000 7237 ns/op 5616 B/op 39 allocs/op
386 | BenchmarkChi_ParseStatic 3000000 408 ns/op 432 B/op 3 allocs/op
387 | BenchmarkChi_ParseParam 3000000 488 ns/op 432 B/op 3 allocs/op
388 | BenchmarkChi_Parse2Params 3000000 551 ns/op 432 B/op 3 allocs/op
389 | BenchmarkChi_ParseAll 100000 13508 ns/op 11232 B/op 78 allocs/op
390 | BenchmarkChi_StaticAll 20000 81933 ns/op 67826 B/op 471 allocs/op
391 | ```
392 |
393 | Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
394 |
395 | NOTE: the allocs in the benchmark above are from the calls to http.Request's
396 | `WithContext(context.Context)` method that clones the http.Request, sets the `Context()`
397 | on the duplicated (alloc'd) request and returns it the new request object. This is just
398 | how setting context on a request in Go works.
399 |
400 |
401 | ## Credits
402 |
403 | * Carl Jackson for https://github.com/zenazn/goji
404 | * Parts of chi's thinking comes from goji, and chi's middleware package
405 | sources from goji.
406 | * Armon Dadgar for https://github.com/armon/go-radix
407 | * Contributions: [@VojtechVitek](https://github.com/VojtechVitek)
408 |
409 | We'll be more than happy to see [your contributions](./CONTRIBUTING.md)!
410 |
411 |
412 | ## Beyond REST
413 |
414 | chi is just a http router that lets you decompose request handling into many smaller layers.
415 | Many companies including Pressly.com (of course) use chi to write REST services for their public
416 | APIs. But, REST is just a convention for managing state via HTTP, and there's a lot of other pieces
417 | required to write a complete client-server system or network of microservices.
418 |
419 | Looking ahead beyond REST, I also recommend some newer works in the field coming from
420 | [gRPC](https://github.com/grpc/grpc-go), [NATS](https://nats.io), [go-kit](https://github.com/go-kit/kit)
421 | and even [graphql](https://github.com/graphql-go/graphql). They're all pretty cool with their
422 | own unique approaches and benefits. Specifically, I'd look at gRPC since it makes client-server
423 | communication feel like a single program on a single computer, no need to hand-write a client library
424 | and the request/response payloads are typed contracts. NATS is pretty amazing too as a super
425 | fast and lightweight pub-sub transport that can speak protobufs, with nice service discovery -
426 | an excellent combination with gRPC.
427 |
428 |
429 | ## License
430 |
431 | Copyright (c) 2015-present [Peter Kieltyka](https://github.com/pkieltyka)
432 |
433 | Licensed under [MIT License](./LICENSE)
434 |
435 | [GoDoc]: https://godoc.org/github.com/go-chi/chi
436 | [GoDoc Widget]: https://godoc.org/github.com/go-chi/chi?status.svg
437 | [Travis]: https://travis-ci.org/go-chi/chi
438 | [Travis Widget]: https://travis-ci.org/go-chi/chi.svg?branch=master
439 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/chain.go:
--------------------------------------------------------------------------------
1 | package chi
2 |
3 | import "net/http"
4 |
5 | // Chain returns a Middlewares type from a slice of middleware handlers.
6 | func Chain(middlewares ...func(http.Handler) http.Handler) Middlewares {
7 | return Middlewares(middlewares)
8 | }
9 |
10 | // Handler builds and returns a http.Handler from the chain of middlewares,
11 | // with `h http.Handler` as the final handler.
12 | func (mws Middlewares) Handler(h http.Handler) http.Handler {
13 | return &ChainHandler{mws, h, chain(mws, h)}
14 | }
15 |
16 | // HandlerFunc builds and returns a http.Handler from the chain of middlewares,
17 | // with `h http.Handler` as the final handler.
18 | func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler {
19 | return &ChainHandler{mws, h, chain(mws, h)}
20 | }
21 |
22 | // ChainHandler is a http.Handler with support for handler composition and
23 | // execution.
24 | type ChainHandler struct {
25 | Middlewares Middlewares
26 | Endpoint http.Handler
27 | chain http.Handler
28 | }
29 |
30 | func (c *ChainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
31 | c.chain.ServeHTTP(w, r)
32 | }
33 |
34 | // chain builds a http.Handler composed of an inline middleware stack and endpoint
35 | // handler in the order they are passed.
36 | func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler {
37 | // Return ahead of time if there aren't any middlewares for the chain
38 | if len(middlewares) == 0 {
39 | return endpoint
40 | }
41 |
42 | // Wrap the end handler with the middleware chain
43 | h := middlewares[len(middlewares)-1](endpoint)
44 | for i := len(middlewares) - 2; i >= 0; i-- {
45 | h = middlewares[i](h)
46 | }
47 |
48 | return h
49 | }
50 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/chi.go:
--------------------------------------------------------------------------------
1 | //
2 | // Package chi is a small, idiomatic and composable router for building HTTP services.
3 | //
4 | // chi requires Go 1.7 or newer.
5 | //
6 | // Example:
7 | // package main
8 | //
9 | // import (
10 | // "net/http"
11 | //
12 | // "github.com/go-chi/chi"
13 | // "github.com/go-chi/chi/middleware"
14 | // )
15 | //
16 | // func main() {
17 | // r := chi.NewRouter()
18 | // r.Use(middleware.Logger)
19 | // r.Use(middleware.Recoverer)
20 | //
21 | // r.Get("/", func(w http.ResponseWriter, r *http.Request) {
22 | // w.Write([]byte("root."))
23 | // })
24 | //
25 | // http.ListenAndServe(":3333", r)
26 | // }
27 | //
28 | // See github.com/go-chi/chi/_examples/ for more in-depth examples.
29 | //
30 | // URL patterns allow for easy matching of path components in HTTP
31 | // requests. The matching components can then be accessed using
32 | // chi.URLParam(). All patterns must begin with a slash.
33 | //
34 | // A simple named placeholder {name} matches any sequence of characters
35 | // up to the next / or the end of the URL. Trailing slashes on paths must
36 | // be handled explicitly.
37 | //
38 | // A placeholder with a name followed by a colon allows a regular
39 | // expression match, for example {number:\\d+}. The regular expression
40 | // syntax is Go's normal regexp RE2 syntax, except that regular expressions
41 | // including { or } are not supported, and / will never be
42 | // matched. An anonymous regexp pattern is allowed, using an empty string
43 | // before the colon in the placeholder, such as {:\\d+}
44 | //
45 | // The special placeholder of asterisk matches the rest of the requested
46 | // URL. Any trailing characters in the pattern are ignored. This is the only
47 | // placeholder which will match / characters.
48 | //
49 | // Examples:
50 | // "/user/{name}" matches "/user/jsmith" but not "/user/jsmith/info" or "/user/jsmith/"
51 | // "/user/{name}/info" matches "/user/jsmith/info"
52 | // "/page/*" matches "/page/intro/latest"
53 | // "/page/*/index" also matches "/page/intro/latest"
54 | // "/date/{yyyy:\\d\\d\\d\\d}/{mm:\\d\\d}/{dd:\\d\\d}" matches "/date/2017/04/01"
55 | //
56 | package chi
57 |
58 | import "net/http"
59 |
60 | // NewRouter returns a new Mux object that implements the Router interface.
61 | func NewRouter() *Mux {
62 | return NewMux()
63 | }
64 |
65 | // Router consisting of the core routing methods used by chi's Mux,
66 | // using only the standard net/http.
67 | type Router interface {
68 | http.Handler
69 | Routes
70 |
71 | // Use appends one of more middlewares onto the Router stack.
72 | Use(middlewares ...func(http.Handler) http.Handler)
73 |
74 | // With adds inline middlewares for an endpoint handler.
75 | With(middlewares ...func(http.Handler) http.Handler) Router
76 |
77 | // Group adds a new inline-Router along the current routing
78 | // path, with a fresh middleware stack for the inline-Router.
79 | Group(fn func(r Router)) Router
80 |
81 | // Route mounts a sub-Router along a `pattern`` string.
82 | Route(pattern string, fn func(r Router)) Router
83 |
84 | // Mount attaches another http.Handler along ./pattern/*
85 | Mount(pattern string, h http.Handler)
86 |
87 | // Handle and HandleFunc adds routes for `pattern` that matches
88 | // all HTTP methods.
89 | Handle(pattern string, h http.Handler)
90 | HandleFunc(pattern string, h http.HandlerFunc)
91 |
92 | // Method and MethodFunc adds routes for `pattern` that matches
93 | // the `method` HTTP method.
94 | Method(method, pattern string, h http.Handler)
95 | MethodFunc(method, pattern string, h http.HandlerFunc)
96 |
97 | // HTTP-method routing along `pattern`
98 | Connect(pattern string, h http.HandlerFunc)
99 | Delete(pattern string, h http.HandlerFunc)
100 | Get(pattern string, h http.HandlerFunc)
101 | Head(pattern string, h http.HandlerFunc)
102 | Options(pattern string, h http.HandlerFunc)
103 | Patch(pattern string, h http.HandlerFunc)
104 | Post(pattern string, h http.HandlerFunc)
105 | Put(pattern string, h http.HandlerFunc)
106 | Trace(pattern string, h http.HandlerFunc)
107 |
108 | // NotFound defines a handler to respond whenever a route could
109 | // not be found.
110 | NotFound(h http.HandlerFunc)
111 |
112 | // MethodNotAllowed defines a handler to respond whenever a method is
113 | // not allowed.
114 | MethodNotAllowed(h http.HandlerFunc)
115 | }
116 |
117 | // Routes interface adds two methods for router traversal, which is also
118 | // used by the `docgen` subpackage to generation documentation for Routers.
119 | type Routes interface {
120 | // Routes returns the routing tree in an easily traversable structure.
121 | Routes() []Route
122 |
123 | // Middlewares returns the list of middlewares in use by the router.
124 | Middlewares() Middlewares
125 |
126 | // Match searches the routing tree for a handler that matches
127 | // the method/path - similar to routing a http request, but without
128 | // executing the handler thereafter.
129 | Match(rctx *Context, method, path string) bool
130 | }
131 |
132 | // Middlewares type is a slice of standard middleware handlers with methods
133 | // to compose middleware chains and http.Handler's.
134 | type Middlewares []func(http.Handler) http.Handler
135 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/context.go:
--------------------------------------------------------------------------------
1 | package chi
2 |
3 | import (
4 | "context"
5 | "net"
6 | "net/http"
7 | "strings"
8 | )
9 |
10 | var (
11 | // RouteCtxKey is the context.Context key to store the request context.
12 | RouteCtxKey = &contextKey{"RouteContext"}
13 | )
14 |
15 | // Context is the default routing context set on the root node of a
16 | // request context to track route patterns, URL parameters and
17 | // an optional routing path.
18 | type Context struct {
19 | Routes Routes
20 |
21 | // Routing path/method override used during the route search.
22 | // See Mux#routeHTTP method.
23 | RoutePath string
24 | RouteMethod string
25 |
26 | // Routing pattern stack throughout the lifecycle of the request,
27 | // across all connected routers. It is a record of all matching
28 | // patterns across a stack of sub-routers.
29 | RoutePatterns []string
30 |
31 | // URLParams are the stack of routeParams captured during the
32 | // routing lifecycle across a stack of sub-routers.
33 | URLParams RouteParams
34 |
35 | // The endpoint routing pattern that matched the request URI path
36 | // or `RoutePath` of the current sub-router. This value will update
37 | // during the lifecycle of a request passing through a stack of
38 | // sub-routers.
39 | routePattern string
40 |
41 | // Route parameters matched for the current sub-router. It is
42 | // intentionally unexported so it cant be tampered.
43 | routeParams RouteParams
44 |
45 | // methodNotAllowed hint
46 | methodNotAllowed bool
47 | }
48 |
49 | // NewRouteContext returns a new routing Context object.
50 | func NewRouteContext() *Context {
51 | return &Context{}
52 | }
53 |
54 | // Reset a routing context to its initial state.
55 | func (x *Context) Reset() {
56 | x.Routes = nil
57 | x.RoutePath = ""
58 | x.RouteMethod = ""
59 | x.RoutePatterns = x.RoutePatterns[:0]
60 | x.URLParams.Keys = x.URLParams.Keys[:0]
61 | x.URLParams.Values = x.URLParams.Values[:0]
62 |
63 | x.routePattern = ""
64 | x.routeParams.Keys = x.routeParams.Keys[:0]
65 | x.routeParams.Values = x.routeParams.Values[:0]
66 | x.methodNotAllowed = false
67 | }
68 |
69 | // URLParam returns the corresponding URL parameter value from the request
70 | // routing context.
71 | func (x *Context) URLParam(key string) string {
72 | for k := len(x.URLParams.Keys) - 1; k >= 0; k-- {
73 | if x.URLParams.Keys[k] == key {
74 | return x.URLParams.Values[k]
75 | }
76 | }
77 | return ""
78 | }
79 |
80 | // RoutePattern builds the routing pattern string for the particular
81 | // request, at the particular point during routing. This means, the value
82 | // will change throughout the execution of a request in a router. That is
83 | // why its advised to only use this value after calling the next handler.
84 | //
85 | // For example,
86 | //
87 | // func Instrument(next http.Handler) http.Handler {
88 | // return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
89 | // next.ServeHTTP(w, r)
90 | // routePattern := chi.RouteContext(r.Context()).RoutePattern()
91 | // measure(w, r, routePattern)
92 | // })
93 | // }
94 | func (x *Context) RoutePattern() string {
95 | routePattern := strings.Join(x.RoutePatterns, "")
96 | return strings.Replace(routePattern, "/*/", "/", -1)
97 | }
98 |
99 | // RouteContext returns chi's routing Context object from a
100 | // http.Request Context.
101 | func RouteContext(ctx context.Context) *Context {
102 | return ctx.Value(RouteCtxKey).(*Context)
103 | }
104 |
105 | // URLParam returns the url parameter from a http.Request object.
106 | func URLParam(r *http.Request, key string) string {
107 | if rctx := RouteContext(r.Context()); rctx != nil {
108 | return rctx.URLParam(key)
109 | }
110 | return ""
111 | }
112 |
113 | // URLParamFromCtx returns the url parameter from a http.Request Context.
114 | func URLParamFromCtx(ctx context.Context, key string) string {
115 | if rctx := RouteContext(ctx); rctx != nil {
116 | return rctx.URLParam(key)
117 | }
118 | return ""
119 | }
120 |
121 | // RouteParams is a structure to track URL routing parameters efficiently.
122 | type RouteParams struct {
123 | Keys, Values []string
124 | }
125 |
126 | // Add will append a URL parameter to the end of the route param
127 | func (s *RouteParams) Add(key, value string) {
128 | (*s).Keys = append((*s).Keys, key)
129 | (*s).Values = append((*s).Values, value)
130 | }
131 |
132 | // ServerBaseContext wraps an http.Handler to set the request context to the
133 | // `baseCtx`.
134 | func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler {
135 | fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
136 | ctx := r.Context()
137 | baseCtx := baseCtx
138 |
139 | // Copy over default net/http server context keys
140 | if v, ok := ctx.Value(http.ServerContextKey).(*http.Server); ok {
141 | baseCtx = context.WithValue(baseCtx, http.ServerContextKey, v)
142 | }
143 | if v, ok := ctx.Value(http.LocalAddrContextKey).(net.Addr); ok {
144 | baseCtx = context.WithValue(baseCtx, http.LocalAddrContextKey, v)
145 | }
146 |
147 | h.ServeHTTP(w, r.WithContext(baseCtx))
148 | })
149 | return fn
150 | }
151 |
152 | // contextKey is a value for use with context.WithValue. It's used as
153 | // a pointer so it fits in an interface{} without allocation. This technique
154 | // for defining context keys was copied from Go 1.7's new use of context in net/http.
155 | type contextKey struct {
156 | name string
157 | }
158 |
159 | func (k *contextKey) String() string {
160 | return "chi context value " + k.name
161 | }
162 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/chi/mux.go:
--------------------------------------------------------------------------------
1 | package chi
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "net/http"
7 | "strings"
8 | "sync"
9 | )
10 |
11 | var _ Router = &Mux{}
12 |
13 | // Mux is a simple HTTP route multiplexer that parses a request path,
14 | // records any URL params, and executes an end handler. It implements
15 | // the http.Handler interface and is friendly with the standard library.
16 | //
17 | // Mux is designed to be fast, minimal and offer a powerful API for building
18 | // modular and composable HTTP services with a large set of handlers. It's
19 | // particularly useful for writing large REST API services that break a handler
20 | // into many smaller parts composed of middlewares and end handlers.
21 | type Mux struct {
22 | // The radix trie router
23 | tree *node
24 |
25 | // The middleware stack
26 | middlewares []func(http.Handler) http.Handler
27 |
28 | // Controls the behaviour of middleware chain generation when a mux
29 | // is registered as an inline group inside another mux.
30 | inline bool
31 | parent *Mux
32 |
33 | // The computed mux handler made of the chained middleware stack and
34 | // the tree router
35 | handler http.Handler
36 |
37 | // Routing context pool
38 | pool *sync.Pool
39 |
40 | // Custom route not found handler
41 | notFoundHandler http.HandlerFunc
42 |
43 | // Custom method not allowed handler
44 | methodNotAllowedHandler http.HandlerFunc
45 | }
46 |
47 | // NewMux returns a newly initialized Mux object that implements the Router
48 | // interface.
49 | func NewMux() *Mux {
50 | mux := &Mux{tree: &node{}, pool: &sync.Pool{}}
51 | mux.pool.New = func() interface{} {
52 | return NewRouteContext()
53 | }
54 | return mux
55 | }
56 |
57 | // ServeHTTP is the single method of the http.Handler interface that makes
58 | // Mux interoperable with the standard library. It uses a sync.Pool to get and
59 | // reuse routing contexts for each request.
60 | func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
61 | // Ensure the mux has some routes defined on the mux
62 | if mx.handler == nil {
63 | mx.NotFoundHandler().ServeHTTP(w, r)
64 | return
65 | }
66 |
67 | // Check if a routing context already exists from a parent router.
68 | rctx, _ := r.Context().Value(RouteCtxKey).(*Context)
69 | if rctx != nil {
70 | mx.handler.ServeHTTP(w, r)
71 | return
72 | }
73 |
74 | // Fetch a RouteContext object from the sync pool, and call the computed
75 | // mx.handler that is comprised of mx.middlewares + mx.routeHTTP.
76 | // Once the request is finished, reset the routing context and put it back
77 | // into the pool for reuse from another request.
78 | rctx = mx.pool.Get().(*Context)
79 | rctx.Reset()
80 | rctx.Routes = mx
81 | r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx))
82 | mx.handler.ServeHTTP(w, r)
83 | mx.pool.Put(rctx)
84 | }
85 |
86 | // Use appends a middleware handler to the Mux middleware stack.
87 | //
88 | // The middleware stack for any Mux will execute before searching for a matching
89 | // route to a specific handler, which provides opportunity to respond early,
90 | // change the course of the request execution, or set request-scoped values for
91 | // the next http.Handler.
92 | func (mx *Mux) Use(middlewares ...func(http.Handler) http.Handler) {
93 | if mx.handler != nil {
94 | panic("chi: all middlewares must be defined before routes on a mux")
95 | }
96 | mx.middlewares = append(mx.middlewares, middlewares...)
97 | }
98 |
99 | // Handle adds the route `pattern` that matches any http method to
100 | // execute the `handler` http.Handler.
101 | func (mx *Mux) Handle(pattern string, handler http.Handler) {
102 | mx.handle(mALL, pattern, handler)
103 | }
104 |
105 | // HandleFunc adds the route `pattern` that matches any http method to
106 | // execute the `handlerFn` http.HandlerFunc.
107 | func (mx *Mux) HandleFunc(pattern string, handlerFn http.HandlerFunc) {
108 | mx.handle(mALL, pattern, handlerFn)
109 | }
110 |
111 | // Method adds the route `pattern` that matches `method` http method to
112 | // execute the `handler` http.Handler.
113 | func (mx *Mux) Method(method, pattern string, handler http.Handler) {
114 | m, ok := methodMap[strings.ToUpper(method)]
115 | if !ok {
116 | panic(fmt.Sprintf("chi: '%s' http method is not supported.", method))
117 | }
118 | mx.handle(m, pattern, handler)
119 | }
120 |
121 | // MethodFunc adds the route `pattern` that matches `method` http method to
122 | // execute the `handlerFn` http.HandlerFunc.
123 | func (mx *Mux) MethodFunc(method, pattern string, handlerFn http.HandlerFunc) {
124 | mx.Method(method, pattern, handlerFn)
125 | }
126 |
127 | // Connect adds the route `pattern` that matches a CONNECT http method to
128 | // execute the `handlerFn` http.HandlerFunc.
129 | func (mx *Mux) Connect(pattern string, handlerFn http.HandlerFunc) {
130 | mx.handle(mCONNECT, pattern, handlerFn)
131 | }
132 |
133 | // Delete adds the route `pattern` that matches a DELETE http method to
134 | // execute the `handlerFn` http.HandlerFunc.
135 | func (mx *Mux) Delete(pattern string, handlerFn http.HandlerFunc) {
136 | mx.handle(mDELETE, pattern, handlerFn)
137 | }
138 |
139 | // Get adds the route `pattern` that matches a GET http method to
140 | // execute the `handlerFn` http.HandlerFunc.
141 | func (mx *Mux) Get(pattern string, handlerFn http.HandlerFunc) {
142 | mx.handle(mGET, pattern, handlerFn)
143 | }
144 |
145 | // Head adds the route `pattern` that matches a HEAD http method to
146 | // execute the `handlerFn` http.HandlerFunc.
147 | func (mx *Mux) Head(pattern string, handlerFn http.HandlerFunc) {
148 | mx.handle(mHEAD, pattern, handlerFn)
149 | }
150 |
151 | // Options adds the route `pattern` that matches a OPTIONS http method to
152 | // execute the `handlerFn` http.HandlerFunc.
153 | func (mx *Mux) Options(pattern string, handlerFn http.HandlerFunc) {
154 | mx.handle(mOPTIONS, pattern, handlerFn)
155 | }
156 |
157 | // Patch adds the route `pattern` that matches a PATCH http method to
158 | // execute the `handlerFn` http.HandlerFunc.
159 | func (mx *Mux) Patch(pattern string, handlerFn http.HandlerFunc) {
160 | mx.handle(mPATCH, pattern, handlerFn)
161 | }
162 |
163 | // Post adds the route `pattern` that matches a POST http method to
164 | // execute the `handlerFn` http.HandlerFunc.
165 | func (mx *Mux) Post(pattern string, handlerFn http.HandlerFunc) {
166 | mx.handle(mPOST, pattern, handlerFn)
167 | }
168 |
169 | // Put adds the route `pattern` that matches a PUT http method to
170 | // execute the `handlerFn` http.HandlerFunc.
171 | func (mx *Mux) Put(pattern string, handlerFn http.HandlerFunc) {
172 | mx.handle(mPUT, pattern, handlerFn)
173 | }
174 |
175 | // Trace adds the route `pattern` that matches a TRACE http method to
176 | // execute the `handlerFn` http.HandlerFunc.
177 | func (mx *Mux) Trace(pattern string, handlerFn http.HandlerFunc) {
178 | mx.handle(mTRACE, pattern, handlerFn)
179 | }
180 |
181 | // NotFound sets a custom http.HandlerFunc for routing paths that could
182 | // not be found. The default 404 handler is `http.NotFound`.
183 | func (mx *Mux) NotFound(handlerFn http.HandlerFunc) {
184 | // Build NotFound handler chain
185 | m := mx
186 | hFn := handlerFn
187 | if mx.inline && mx.parent != nil {
188 | m = mx.parent
189 | hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP
190 | }
191 |
192 | // Update the notFoundHandler from this point forward
193 | m.notFoundHandler = hFn
194 | m.updateSubRoutes(func(subMux *Mux) {
195 | if subMux.notFoundHandler == nil {
196 | subMux.NotFound(hFn)
197 | }
198 | })
199 | }
200 |
201 | // MethodNotAllowed sets a custom http.HandlerFunc for routing paths where the
202 | // method is unresolved. The default handler returns a 405 with an empty body.
203 | func (mx *Mux) MethodNotAllowed(handlerFn http.HandlerFunc) {
204 | // Build MethodNotAllowed handler chain
205 | m := mx
206 | hFn := handlerFn
207 | if mx.inline && mx.parent != nil {
208 | m = mx.parent
209 | hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP
210 | }
211 |
212 | // Update the methodNotAllowedHandler from this point forward
213 | m.methodNotAllowedHandler = hFn
214 | m.updateSubRoutes(func(subMux *Mux) {
215 | if subMux.methodNotAllowedHandler == nil {
216 | subMux.MethodNotAllowed(hFn)
217 | }
218 | })
219 | }
220 |
221 | // With adds inline middlewares for an endpoint handler.
222 | func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router {
223 | // Similarly as in handle(), we must build the mux handler once further
224 | // middleware registration isn't allowed for this stack, like now.
225 | if !mx.inline && mx.handler == nil {
226 | mx.buildRouteHandler()
227 | }
228 |
229 | // Copy middlewares from parent inline muxs
230 | var mws Middlewares
231 | if mx.inline {
232 | mws = make(Middlewares, len(mx.middlewares))
233 | copy(mws, mx.middlewares)
234 | }
235 | mws = append(mws, middlewares...)
236 |
237 | im := &Mux{pool: mx.pool, inline: true, parent: mx, tree: mx.tree, middlewares: mws}
238 |
239 | return im
240 | }
241 |
242 | // Group creates a new inline-Mux with a fresh middleware stack. It's useful
243 | // for a group of handlers along the same routing path that use an additional
244 | // set of middlewares. See _examples/.
245 | func (mx *Mux) Group(fn func(r Router)) Router {
246 | im := mx.With().(*Mux)
247 | if fn != nil {
248 | fn(im)
249 | }
250 | return im
251 | }
252 |
253 | // Route creates a new Mux with a fresh middleware stack and mounts it
254 | // along the `pattern` as a subrouter. Effectively, this is a short-hand
255 | // call to Mount. See _examples/.
256 | func (mx *Mux) Route(pattern string, fn func(r Router)) Router {
257 | subRouter := NewRouter()
258 | if fn != nil {
259 | fn(subRouter)
260 | }
261 | mx.Mount(pattern, subRouter)
262 | return subRouter
263 | }
264 |
265 | // Mount attaches another http.Handler or chi Router as a subrouter along a routing
266 | // path. It's very useful to split up a large API as many independent routers and
267 | // compose them as a single service using Mount. See _examples/.
268 | //
269 | // Note that Mount() simply sets a wildcard along the `pattern` that will continue
270 | // routing at the `handler`, which in most cases is another chi.Router. As a result,
271 | // if you define two Mount() routes on the exact same pattern the mount will panic.
272 | func (mx *Mux) Mount(pattern string, handler http.Handler) {
273 | // Provide runtime safety for ensuring a pattern isn't mounted on an existing
274 | // routing pattern.
275 | if mx.tree.findPattern(pattern+"*") || mx.tree.findPattern(pattern+"/*") {
276 | panic(fmt.Sprintf("chi: attempting to Mount() a handler on an existing path, '%s'", pattern))
277 | }
278 |
279 | // Assign sub-Router's with the parent not found & method not allowed handler if not specified.
280 | subr, ok := handler.(*Mux)
281 | if ok && subr.notFoundHandler == nil && mx.notFoundHandler != nil {
282 | subr.NotFound(mx.notFoundHandler)
283 | }
284 | if ok && subr.methodNotAllowedHandler == nil && mx.methodNotAllowedHandler != nil {
285 | subr.MethodNotAllowed(mx.methodNotAllowedHandler)
286 | }
287 |
288 | // Wrap the sub-router in a handlerFunc to scope the request path for routing.
289 | mountHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
290 | rctx := RouteContext(r.Context())
291 | rctx.RoutePath = mx.nextRoutePath(rctx)
292 | handler.ServeHTTP(w, r)
293 | })
294 |
295 | if pattern == "" || pattern[len(pattern)-1] != '/' {
296 | mx.handle(mALL|mSTUB, pattern, mountHandler)
297 | mx.handle(mALL|mSTUB, pattern+"/", mountHandler)
298 | pattern += "/"
299 | }
300 |
301 | method := mALL
302 | subroutes, _ := handler.(Routes)
303 | if subroutes != nil {
304 | method |= mSTUB
305 | }
306 | n := mx.handle(method, pattern+"*", mountHandler)
307 |
308 | if subroutes != nil {
309 | n.subroutes = subroutes
310 | }
311 | }
312 |
313 | // Routes returns a slice of routing information from the tree,
314 | // useful for traversing available routes of a router.
315 | func (mx *Mux) Routes() []Route {
316 | return mx.tree.routes()
317 | }
318 |
319 | // Middlewares returns a slice of middleware handler functions.
320 | func (mx *Mux) Middlewares() Middlewares {
321 | return mx.middlewares
322 | }
323 |
324 | // Match searches the routing tree for a handler that matches the method/path.
325 | // It's similar to routing a http request, but without executing the handler
326 | // thereafter.
327 | //
328 | // Note: the *Context state is updated during execution, so manage
329 | // the state carefully or make a NewRouteContext().
330 | func (mx *Mux) Match(rctx *Context, method, path string) bool {
331 | m, ok := methodMap[method]
332 | if !ok {
333 | return false
334 | }
335 |
336 | node, _, h := mx.tree.FindRoute(rctx, m, path)
337 |
338 | if node != nil && node.subroutes != nil {
339 | rctx.RoutePath = mx.nextRoutePath(rctx)
340 | return node.subroutes.Match(rctx, method, rctx.RoutePath)
341 | }
342 |
343 | return h != nil
344 | }
345 |
346 | // NotFoundHandler returns the default Mux 404 responder whenever a route
347 | // cannot be found.
348 | func (mx *Mux) NotFoundHandler() http.HandlerFunc {
349 | if mx.notFoundHandler != nil {
350 | return mx.notFoundHandler
351 | }
352 | return http.NotFound
353 | }
354 |
355 | // MethodNotAllowedHandler returns the default Mux 405 responder whenever
356 | // a method cannot be resolved for a route.
357 | func (mx *Mux) MethodNotAllowedHandler() http.HandlerFunc {
358 | if mx.methodNotAllowedHandler != nil {
359 | return mx.methodNotAllowedHandler
360 | }
361 | return methodNotAllowedHandler
362 | }
363 |
364 | // buildRouteHandler builds the single mux handler that is a chain of the middleware
365 | // stack, as defined by calls to Use(), and the tree router (Mux) itself. After this
366 | // point, no other middlewares can be registered on this Mux's stack. But you can still
367 | // compose additional middlewares via Group()'s or using a chained middleware handler.
368 | func (mx *Mux) buildRouteHandler() {
369 | mx.handler = chain(mx.middlewares, http.HandlerFunc(mx.routeHTTP))
370 | }
371 |
372 | // handle registers a http.Handler in the routing tree for a particular http method
373 | // and routing pattern.
374 | func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *node {
375 | if len(pattern) == 0 || pattern[0] != '/' {
376 | panic(fmt.Sprintf("chi: routing pattern must begin with '/' in '%s'", pattern))
377 | }
378 |
379 | // Build the final routing handler for this Mux.
380 | if !mx.inline && mx.handler == nil {
381 | mx.buildRouteHandler()
382 | }
383 |
384 | // Build endpoint handler with inline middlewares for the route
385 | var h http.Handler
386 | if mx.inline {
387 | mx.handler = http.HandlerFunc(mx.routeHTTP)
388 | h = Chain(mx.middlewares...).Handler(handler)
389 | } else {
390 | h = handler
391 | }
392 |
393 | // Add the endpoint to the tree and return the node
394 | return mx.tree.InsertRoute(method, pattern, h)
395 | }
396 |
397 | // routeHTTP routes a http.Request through the Mux routing tree to serve
398 | // the matching handler for a particular http method.
399 | func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
400 | // Grab the route context object
401 | rctx := r.Context().Value(RouteCtxKey).(*Context)
402 |
403 | // The request routing path
404 | routePath := rctx.RoutePath
405 | if routePath == "" {
406 | if r.URL.RawPath != "" {
407 | routePath = r.URL.RawPath
408 | } else {
409 | routePath = r.URL.Path
410 | }
411 | }
412 |
413 | // Check if method is supported by chi
414 | if rctx.RouteMethod == "" {
415 | rctx.RouteMethod = r.Method
416 | }
417 | method, ok := methodMap[rctx.RouteMethod]
418 | if !ok {
419 | mx.MethodNotAllowedHandler().ServeHTTP(w, r)
420 | return
421 | }
422 |
423 | // Find the route
424 | if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
425 | h.ServeHTTP(w, r)
426 | return
427 | }
428 | if rctx.methodNotAllowed {
429 | mx.MethodNotAllowedHandler().ServeHTTP(w, r)
430 | } else {
431 | mx.NotFoundHandler().ServeHTTP(w, r)
432 | }
433 | }
434 |
435 | func (mx *Mux) nextRoutePath(rctx *Context) string {
436 | routePath := "/"
437 | nx := len(rctx.routeParams.Keys) - 1 // index of last param in list
438 | if nx >= 0 && rctx.routeParams.Keys[nx] == "*" && len(rctx.routeParams.Values) > nx {
439 | routePath += rctx.routeParams.Values[nx]
440 | }
441 | return routePath
442 | }
443 |
444 | // Recursively update data on child routers.
445 | func (mx *Mux) updateSubRoutes(fn func(subMux *Mux)) {
446 | for _, r := range mx.tree.routes() {
447 | subMux, ok := r.SubRoutes.(*Mux)
448 | if !ok {
449 | continue
450 | }
451 | fn(subMux)
452 | }
453 | }
454 |
455 | // methodNotAllowedHandler is a helper function to respond with a 405,
456 | // method not allowed.
457 | func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {
458 | w.WriteHeader(405)
459 | w.Write(nil)
460 | }
461 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/cors/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Olivier Poitrey
2 | Copyright (c) 2016-Present https://github.com/go-chi authors
3 |
4 | MIT License
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of
7 | this software and associated documentation files (the "Software"), to deal in
8 | the Software without restriction, including without limitation the rights to
9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software is furnished to do so,
11 | subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/cors/README.md:
--------------------------------------------------------------------------------
1 | # CORS net/http middleware
2 |
3 | [go-chi/cors](https://github.com/go-chi/cors) is a fork of github.com/rs/cors that provides a `net/http` compatible middleware for performing preflight CORS checks on the server side. These headers are required for using the browser native [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
4 |
5 | This middleware is designed to be used as a global middleware on the chi router. Applying with within a `r.Group()` or using `With()` will not work without routes matching `OPTIONS` added.
6 |
7 | ## Usage
8 |
9 | ```go
10 | func main() {
11 | r := chi.NewRouter()
12 |
13 | // Basic CORS
14 | // for more ideas, see: https://developer.github.com/v3/#cross-origin-resource-sharing
15 | cors := cors.New(cors.Options{
16 | // AllowedOrigins: []string{"https://foo.com"}, // Use this to allow specific origin hosts
17 | AllowedOrigins: []string{"*"},
18 | // AllowOriginFunc: func(r *http.Request, origin string) bool { return true },
19 | AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
20 | AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
21 | ExposedHeaders: []string{"Link"},
22 | AllowCredentials: true,
23 | MaxAge: 300, // Maximum value not ignored by any of major browsers
24 | })
25 | r.Use(cors.Handler)
26 |
27 | r.Get("/", func(w http.ResponseWriter, r *http.Request) {
28 | w.Write([]byte("welcome"))
29 | })
30 |
31 | http.ListenAndServe(":3000", r)
32 | }
33 | ```
34 |
35 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/cors/cors.go:
--------------------------------------------------------------------------------
1 | // cors package is net/http handler to handle CORS related requests
2 | // as defined by http://www.w3.org/TR/cors/
3 | //
4 | // You can configure it by passing an option struct to cors.New:
5 | //
6 | // c := cors.New(cors.Options{
7 | // AllowedOrigins: []string{"foo.com"},
8 | // AllowedMethods: []string{"GET", "POST", "DELETE"},
9 | // AllowCredentials: true,
10 | // })
11 | //
12 | // Then insert the handler in the chain:
13 | //
14 | // handler = c.Handler(handler)
15 | //
16 | // See Options documentation for more options.
17 | //
18 | // The resulting handler is a standard net/http handler.
19 | package cors
20 |
21 | import (
22 | "log"
23 | "net/http"
24 | "os"
25 | "strconv"
26 | "strings"
27 | )
28 |
29 | // Options is a configuration container to setup the CORS middleware.
30 | type Options struct {
31 | // AllowedOrigins is a list of origins a cross-domain request can be executed from.
32 | // If the special "*" value is present in the list, all origins will be allowed.
33 | // An origin may contain a wildcard (*) to replace 0 or more characters
34 | // (i.e.: http://*.domain.com). Usage of wildcards implies a small performance penality.
35 | // Only one wildcard can be used per origin.
36 | // Default value is ["*"]
37 | AllowedOrigins []string
38 |
39 | // AllowOriginFunc is a custom function to validate the origin. It take the origin
40 | // as argument and returns true if allowed or false otherwise. If this option is
41 | // set, the content of AllowedOrigins is ignored.
42 | AllowOriginFunc func(r *http.Request, origin string) bool
43 |
44 | // AllowedMethods is a list of methods the client is allowed to use with
45 | // cross-domain requests. Default value is simple methods (GET and POST)
46 | AllowedMethods []string
47 |
48 | // AllowedHeaders is list of non simple headers the client is allowed to use with
49 | // cross-domain requests.
50 | // If the special "*" value is present in the list, all headers will be allowed.
51 | // Default value is [] but "Origin" is always appended to the list.
52 | AllowedHeaders []string
53 |
54 | // ExposedHeaders indicates which headers are safe to expose to the API of a CORS
55 | // API specification
56 | ExposedHeaders []string
57 |
58 | // AllowCredentials indicates whether the request can include user credentials like
59 | // cookies, HTTP authentication or client side SSL certificates.
60 | AllowCredentials bool
61 |
62 | // MaxAge indicates how long (in seconds) the results of a preflight request
63 | // can be cached
64 | MaxAge int
65 |
66 | // OptionsPassthrough instructs preflight to let other potential next handlers to
67 | // process the OPTIONS method. Turn this on if your application handles OPTIONS.
68 | OptionsPassthrough bool
69 |
70 | // Debugging flag adds additional output to debug server side CORS issues
71 | Debug bool
72 | }
73 |
74 | // Cors http handler
75 | type Cors struct {
76 | // Debug logger
77 | log *log.Logger
78 |
79 | // Set to true when allowed origins contains a "*"
80 | allowedOriginsAll bool
81 |
82 | // Normalized list of plain allowed origins
83 | allowedOrigins []string
84 |
85 | // List of allowed origins containing wildcards
86 | allowedWOrigins []wildcard
87 |
88 | // Optional origin validator function
89 | allowOriginFunc func(r *http.Request, origin string) bool
90 |
91 | // Set to true when allowed headers contains a "*"
92 | allowedHeadersAll bool
93 |
94 | // Normalized list of allowed headers
95 | allowedHeaders []string
96 |
97 | // Normalized list of allowed methods
98 | allowedMethods []string
99 |
100 | // Normalized list of exposed headers
101 | exposedHeaders []string
102 | allowCredentials bool
103 | maxAge int
104 | optionPassthrough bool
105 | }
106 |
107 | // New creates a new Cors handler with the provided options.
108 | func New(options Options) *Cors {
109 | c := &Cors{
110 | exposedHeaders: convert(options.ExposedHeaders, http.CanonicalHeaderKey),
111 | allowOriginFunc: options.AllowOriginFunc,
112 | allowCredentials: options.AllowCredentials,
113 | maxAge: options.MaxAge,
114 | optionPassthrough: options.OptionsPassthrough,
115 | }
116 | if options.Debug {
117 | c.log = log.New(os.Stdout, "[cors] ", log.LstdFlags)
118 | }
119 |
120 | // Normalize options
121 | // Note: for origins and methods matching, the spec requires a case-sensitive matching.
122 | // As it may error prone, we chose to ignore the spec here.
123 |
124 | // Allowed Origins
125 | if len(options.AllowedOrigins) == 0 {
126 | // Default is all origins
127 | c.allowedOriginsAll = true
128 | } else {
129 | c.allowedOrigins = []string{}
130 | c.allowedWOrigins = []wildcard{}
131 | for _, origin := range options.AllowedOrigins {
132 | // Normalize
133 | origin = strings.ToLower(origin)
134 | if origin == "*" {
135 | // If "*" is present in the list, turn the whole list into a match all
136 | c.allowedOriginsAll = true
137 | c.allowedOrigins = nil
138 | c.allowedWOrigins = nil
139 | break
140 | } else if i := strings.IndexByte(origin, '*'); i >= 0 {
141 | // Split the origin in two: start and end string without the *
142 | w := wildcard{origin[0:i], origin[i+1 : len(origin)]}
143 | c.allowedWOrigins = append(c.allowedWOrigins, w)
144 | } else {
145 | c.allowedOrigins = append(c.allowedOrigins, origin)
146 | }
147 | }
148 | }
149 |
150 | // Allowed Headers
151 | if len(options.AllowedHeaders) == 0 {
152 | // Use sensible defaults
153 | c.allowedHeaders = []string{"Origin", "Accept", "Content-Type"}
154 | } else {
155 | // Origin is always appended as some browsers will always request for this header at preflight
156 | c.allowedHeaders = convert(append(options.AllowedHeaders, "Origin"), http.CanonicalHeaderKey)
157 | for _, h := range options.AllowedHeaders {
158 | if h == "*" {
159 | c.allowedHeadersAll = true
160 | c.allowedHeaders = nil
161 | break
162 | }
163 | }
164 | }
165 |
166 | // Allowed Methods
167 | if len(options.AllowedMethods) == 0 {
168 | // Default is spec's "simple" methods
169 | c.allowedMethods = []string{"GET", "POST"}
170 | } else {
171 | c.allowedMethods = convert(options.AllowedMethods, strings.ToUpper)
172 | }
173 |
174 | return c
175 | }
176 |
177 | // Default creates a new Cors handler with default options
178 | func Default() *Cors {
179 | return New(Options{})
180 | }
181 |
182 | // Handler apply the CORS specification on the request, and add relevant CORS headers
183 | // as necessary.
184 | func (c *Cors) Handler(next http.Handler) http.Handler {
185 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
186 | if r.Method == "OPTIONS" {
187 | c.logf("Handler: Preflight request")
188 | c.handlePreflight(w, r)
189 | // Preflight requests are standalone and should stop the chain as some other
190 | // middleware may not handle OPTIONS requests correctly. One typical example
191 | // is authentication middleware ; OPTIONS requests won't carry authentication
192 | // headers (see #1)
193 | if c.optionPassthrough {
194 | next.ServeHTTP(w, r)
195 | } else {
196 | w.WriteHeader(http.StatusOK)
197 | }
198 | } else {
199 | c.logf("Handler: Actual request")
200 | c.handleActualRequest(w, r)
201 | next.ServeHTTP(w, r)
202 | }
203 | })
204 | }
205 |
206 | // handlePreflight handles pre-flight CORS requests
207 | func (c *Cors) handlePreflight(w http.ResponseWriter, r *http.Request) {
208 | headers := w.Header()
209 | origin := r.Header.Get("Origin")
210 |
211 | if r.Method != "OPTIONS" {
212 | c.logf("Preflight aborted: %s!=OPTIONS", r.Method)
213 | return
214 | }
215 | // Always set Vary headers
216 | // see https://github.com/rs/cors/issues/10,
217 | // https://github.com/rs/cors/commit/dbdca4d95feaa7511a46e6f1efb3b3aa505bc43f#commitcomment-12352001
218 | headers.Add("Vary", "Origin")
219 | headers.Add("Vary", "Access-Control-Request-Method")
220 | headers.Add("Vary", "Access-Control-Request-Headers")
221 |
222 | if origin == "" {
223 | c.logf("Preflight aborted: empty origin")
224 | return
225 | }
226 | if !c.isOriginAllowed(r, origin) {
227 | c.logf("Preflight aborted: origin '%s' not allowed", origin)
228 | return
229 | }
230 |
231 | reqMethod := r.Header.Get("Access-Control-Request-Method")
232 | if !c.isMethodAllowed(reqMethod) {
233 | c.logf("Preflight aborted: method '%s' not allowed", reqMethod)
234 | return
235 | }
236 | reqHeaders := parseHeaderList(r.Header.Get("Access-Control-Request-Headers"))
237 | if !c.areHeadersAllowed(reqHeaders) {
238 | c.logf("Preflight aborted: headers '%v' not allowed", reqHeaders)
239 | return
240 | }
241 | headers.Set("Access-Control-Allow-Origin", origin)
242 | // Spec says: Since the list of methods can be unbounded, simply returning the method indicated
243 | // by Access-Control-Request-Method (if supported) can be enough
244 | headers.Set("Access-Control-Allow-Methods", strings.ToUpper(reqMethod))
245 | if len(reqHeaders) > 0 {
246 |
247 | // Spec says: Since the list of headers can be unbounded, simply returning supported headers
248 | // from Access-Control-Request-Headers can be enough
249 | headers.Set("Access-Control-Allow-Headers", strings.Join(reqHeaders, ", "))
250 | }
251 | if c.allowCredentials {
252 | headers.Set("Access-Control-Allow-Credentials", "true")
253 | }
254 | if c.maxAge > 0 {
255 | headers.Set("Access-Control-Max-Age", strconv.Itoa(c.maxAge))
256 | }
257 | c.logf("Preflight response headers: %v", headers)
258 | }
259 |
260 | // handleActualRequest handles simple cross-origin requests, actual request or redirects
261 | func (c *Cors) handleActualRequest(w http.ResponseWriter, r *http.Request) {
262 | headers := w.Header()
263 | origin := r.Header.Get("Origin")
264 |
265 | if r.Method == "OPTIONS" {
266 | c.logf("Actual request no headers added: method == %s", r.Method)
267 | return
268 | }
269 | // Always set Vary, see https://github.com/rs/cors/issues/10
270 | headers.Add("Vary", "Origin")
271 | if origin == "" {
272 | c.logf("Actual request no headers added: missing origin")
273 | return
274 | }
275 | if !c.isOriginAllowed(r, origin) {
276 | c.logf("Actual request no headers added: origin '%s' not allowed", origin)
277 | return
278 | }
279 |
280 | // Note that spec does define a way to specifically disallow a simple method like GET or
281 | // POST. Access-Control-Allow-Methods is only used for pre-flight requests and the
282 | // spec doesn't instruct to check the allowed methods for simple cross-origin requests.
283 | // We think it's a nice feature to be able to have control on those methods though.
284 | if !c.isMethodAllowed(r.Method) {
285 | if c.log != nil {
286 | c.logf("Actual request no headers added: method '%s' not allowed",
287 | r.Method)
288 | }
289 |
290 | return
291 | }
292 | headers.Set("Access-Control-Allow-Origin", origin)
293 | if len(c.exposedHeaders) > 0 {
294 | headers.Set("Access-Control-Expose-Headers", strings.Join(c.exposedHeaders, ", "))
295 | }
296 | if c.allowCredentials {
297 | headers.Set("Access-Control-Allow-Credentials", "true")
298 | }
299 | c.logf("Actual response added headers: %v", headers)
300 | }
301 |
302 | // convenience method. checks if debugging is turned on before printing
303 | func (c *Cors) logf(format string, a ...interface{}) {
304 | if c.log != nil {
305 | c.log.Printf(format, a...)
306 | }
307 | }
308 |
309 | // isOriginAllowed checks if a given origin is allowed to perform cross-domain requests
310 | // on the endpoint
311 | func (c *Cors) isOriginAllowed(r *http.Request, origin string) bool {
312 | if c.allowOriginFunc != nil {
313 | return c.allowOriginFunc(r, origin)
314 | }
315 | if c.allowedOriginsAll {
316 | return true
317 | }
318 | origin = strings.ToLower(origin)
319 | for _, o := range c.allowedOrigins {
320 | if o == origin {
321 | return true
322 | }
323 | }
324 | for _, w := range c.allowedWOrigins {
325 | if w.match(origin) {
326 | return true
327 | }
328 | }
329 | return false
330 | }
331 |
332 | // isMethodAllowed checks if a given method can be used as part of a cross-domain request
333 | // on the endpoing
334 | func (c *Cors) isMethodAllowed(method string) bool {
335 | if len(c.allowedMethods) == 0 {
336 | // If no method allowed, always return false, even for preflight request
337 | return false
338 | }
339 | method = strings.ToUpper(method)
340 | if method == "OPTIONS" {
341 | // Always allow preflight requests
342 | return true
343 | }
344 | for _, m := range c.allowedMethods {
345 | if m == method {
346 | return true
347 | }
348 | }
349 | return false
350 | }
351 |
352 | // areHeadersAllowed checks if a given list of headers are allowed to used within
353 | // a cross-domain request.
354 | func (c *Cors) areHeadersAllowed(requestedHeaders []string) bool {
355 | if c.allowedHeadersAll || len(requestedHeaders) == 0 {
356 | return true
357 | }
358 | for _, header := range requestedHeaders {
359 | header = http.CanonicalHeaderKey(header)
360 | found := false
361 | for _, h := range c.allowedHeaders {
362 | if h == header {
363 | found = true
364 | }
365 | }
366 | if !found {
367 | return false
368 | }
369 | }
370 | return true
371 | }
372 |
--------------------------------------------------------------------------------
/vendor/github.com/go-chi/cors/utils.go:
--------------------------------------------------------------------------------
1 | package cors
2 |
3 | import "strings"
4 |
5 | const toLower = 'a' - 'A'
6 |
7 | type converter func(string) string
8 |
9 | type wildcard struct {
10 | prefix string
11 | suffix string
12 | }
13 |
14 | func (w wildcard) match(s string) bool {
15 | return len(s) >= len(w.prefix+w.suffix) && strings.HasPrefix(s, w.prefix) && strings.HasSuffix(s, w.suffix)
16 | }
17 |
18 | // convert converts a list of string using the passed converter function
19 | func convert(s []string, c converter) []string {
20 | out := []string{}
21 | for _, i := range s {
22 | out = append(out, c(i))
23 | }
24 | return out
25 | }
26 |
27 | // parseHeaderList tokenize + normalize a string containing a list of headers
28 | func parseHeaderList(headerList string) []string {
29 | l := len(headerList)
30 | h := make([]byte, 0, l)
31 | upper := true
32 | // Estimate the number headers in order to allocate the right splice size
33 | t := 0
34 | for i := 0; i < l; i++ {
35 | if headerList[i] == ',' {
36 | t++
37 | }
38 | }
39 | headers := make([]string, 0, t)
40 | for i := 0; i < l; i++ {
41 | b := headerList[i]
42 | if b >= 'a' && b <= 'z' {
43 | if upper {
44 | h = append(h, b-toLower)
45 | } else {
46 | h = append(h, b)
47 | }
48 | } else if b >= 'A' && b <= 'Z' {
49 | if !upper {
50 | h = append(h, b+toLower)
51 | } else {
52 | h = append(h, b)
53 | }
54 | } else if b == '-' || (b >= '0' && b <= '9') {
55 | h = append(h, b)
56 | }
57 |
58 | if b == ' ' || b == ',' || i == l-1 {
59 | if len(h) > 0 {
60 | // Flush the found header
61 | headers = append(headers, string(h))
62 | h = h[:0]
63 | upper = true
64 | }
65 | } else {
66 | upper = b == '-'
67 | }
68 | }
69 | return headers
70 | }
71 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | **ATTN**: This project uses [semantic versioning](http://semver.org/).
4 |
5 | ## [Unreleased]
6 |
7 | ## 1.20.0 - 2017-08-10
8 |
9 | ### Fixed
10 |
11 | * `HandleExitCoder` is now correctly iterates over all errors in
12 | a `MultiError`. The exit code is the exit code of the last error or `1` if
13 | there are no `ExitCoder`s in the `MultiError`.
14 | * Fixed YAML file loading on Windows (previously would fail validate the file path)
15 | * Subcommand `Usage`, `Description`, `ArgsUsage`, `OnUsageError` correctly
16 | propogated
17 | * `ErrWriter` is now passed downwards through command structure to avoid the
18 | need to redefine it
19 | * Pass `Command` context into `OnUsageError` rather than parent context so that
20 | all fields are avaiable
21 | * Errors occuring in `Before` funcs are no longer double printed
22 | * Use `UsageText` in the help templates for commands and subcommands if
23 | defined; otherwise build the usage as before (was previously ignoring this
24 | field)
25 | * `IsSet` and `GlobalIsSet` now correctly return whether a flag is set if
26 | a program calls `Set` or `GlobalSet` directly after flag parsing (would
27 | previously only return `true` if the flag was set during parsing)
28 |
29 | ### Changed
30 |
31 | * No longer exit the program on command/subcommand error if the error raised is
32 | not an `OsExiter`. This exiting behavior was introduced in 1.19.0, but was
33 | determined to be a regression in functionality. See [the
34 | PR](https://github.com/urfave/cli/pull/595) for discussion.
35 |
36 | ### Added
37 |
38 | * `CommandsByName` type was added to make it easy to sort `Command`s by name,
39 | alphabetically
40 | * `altsrc` now handles loading of string and int arrays from TOML
41 | * Support for definition of custom help templates for `App` via
42 | `CustomAppHelpTemplate`
43 | * Support for arbitrary key/value fields on `App` to be used with
44 | `CustomAppHelpTemplate` via `ExtraInfo`
45 | * `HelpFlag`, `VersionFlag`, and `BashCompletionFlag` changed to explictly be
46 | `cli.Flag`s allowing for the use of custom flags satisfying the `cli.Flag`
47 | interface to be used.
48 |
49 |
50 | ## [1.19.1] - 2016-11-21
51 |
52 | ### Fixed
53 |
54 | - Fixes regression introduced in 1.19.0 where using an `ActionFunc` as
55 | the `Action` for a command would cause it to error rather than calling the
56 | function. Should not have a affected declarative cases using `func(c
57 | *cli.Context) err)`.
58 | - Shell completion now handles the case where the user specifies
59 | `--generate-bash-completion` immediately after a flag that takes an argument.
60 | Previously it call the application with `--generate-bash-completion` as the
61 | flag value.
62 |
63 | ## [1.19.0] - 2016-11-19
64 | ### Added
65 | - `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`)
66 | - A `Description` field was added to `App` for a more detailed description of
67 | the application (similar to the existing `Description` field on `Command`)
68 | - Flag type code generation via `go generate`
69 | - Write to stderr and exit 1 if action returns non-nil error
70 | - Added support for TOML to the `altsrc` loader
71 | - `SkipArgReorder` was added to allow users to skip the argument reordering.
72 | This is useful if you want to consider all "flags" after an argument as
73 | arguments rather than flags (the default behavior of the stdlib `flag`
74 | library). This is backported functionality from the [removal of the flag
75 | reordering](https://github.com/urfave/cli/pull/398) in the unreleased version
76 | 2
77 | - For formatted errors (those implementing `ErrorFormatter`), the errors will
78 | be formatted during output. Compatible with `pkg/errors`.
79 |
80 | ### Changed
81 | - Raise minimum tested/supported Go version to 1.2+
82 |
83 | ### Fixed
84 | - Consider empty environment variables as set (previously environment variables
85 | with the equivalent of `""` would be skipped rather than their value used).
86 | - Return an error if the value in a given environment variable cannot be parsed
87 | as the flag type. Previously these errors were silently swallowed.
88 | - Print full error when an invalid flag is specified (which includes the invalid flag)
89 | - `App.Writer` defaults to `stdout` when `nil`
90 | - If no action is specified on a command or app, the help is now printed instead of `panic`ing
91 | - `App.Metadata` is initialized automatically now (previously was `nil` unless initialized)
92 | - Correctly show help message if `-h` is provided to a subcommand
93 | - `context.(Global)IsSet` now respects environment variables. Previously it
94 | would return `false` if a flag was specified in the environment rather than
95 | as an argument
96 | - Removed deprecation warnings to STDERR to avoid them leaking to the end-user
97 | - `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This
98 | fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well
99 | as `altsrc` where Go would complain that the types didn't match
100 |
101 | ## [1.18.1] - 2016-08-28
102 | ### Fixed
103 | - Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported)
104 |
105 | ## [1.18.0] - 2016-06-27
106 | ### Added
107 | - `./runtests` test runner with coverage tracking by default
108 | - testing on OS X
109 | - testing on Windows
110 | - `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code
111 |
112 | ### Changed
113 | - Use spaces for alignment in help/usage output instead of tabs, making the
114 | output alignment consistent regardless of tab width
115 |
116 | ### Fixed
117 | - Printing of command aliases in help text
118 | - Printing of visible flags for both struct and struct pointer flags
119 | - Display the `help` subcommand when using `CommandCategories`
120 | - No longer swallows `panic`s that occur within the `Action`s themselves when
121 | detecting the signature of the `Action` field
122 |
123 | ## [1.17.1] - 2016-08-28
124 | ### Fixed
125 | - Removed deprecation warnings to STDERR to avoid them leaking to the end-user
126 |
127 | ## [1.17.0] - 2016-05-09
128 | ### Added
129 | - Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc`
130 | - `context.GlobalBoolT` was added as an analogue to `context.GlobalBool`
131 | - Support for hiding commands by setting `Hidden: true` -- this will hide the
132 | commands in help output
133 |
134 | ### Changed
135 | - `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer
136 | quoted in help text output.
137 | - All flag types now include `(default: {value})` strings following usage when a
138 | default value can be (reasonably) detected.
139 | - `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent
140 | with non-slice flag types
141 | - Apps now exit with a code of 3 if an unknown subcommand is specified
142 | (previously they printed "No help topic for...", but still exited 0. This
143 | makes it easier to script around apps built using `cli` since they can trust
144 | that a 0 exit code indicated a successful execution.
145 | - cleanups based on [Go Report Card
146 | feedback](https://goreportcard.com/report/github.com/urfave/cli)
147 |
148 | ## [1.16.1] - 2016-08-28
149 | ### Fixed
150 | - Removed deprecation warnings to STDERR to avoid them leaking to the end-user
151 |
152 | ## [1.16.0] - 2016-05-02
153 | ### Added
154 | - `Hidden` field on all flag struct types to omit from generated help text
155 |
156 | ### Changed
157 | - `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from
158 | generated help text via the `Hidden` field
159 |
160 | ### Fixed
161 | - handling of error values in `HandleAction` and `HandleExitCoder`
162 |
163 | ## [1.15.0] - 2016-04-30
164 | ### Added
165 | - This file!
166 | - Support for placeholders in flag usage strings
167 | - `App.Metadata` map for arbitrary data/state management
168 | - `Set` and `GlobalSet` methods on `*cli.Context` for altering values after
169 | parsing.
170 | - Support for nested lookup of dot-delimited keys in structures loaded from
171 | YAML.
172 |
173 | ### Changed
174 | - The `App.Action` and `Command.Action` now prefer a return signature of
175 | `func(*cli.Context) error`, as defined by `cli.ActionFunc`. If a non-nil
176 | `error` is returned, there may be two outcomes:
177 | - If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called
178 | automatically
179 | - Else the error is bubbled up and returned from `App.Run`
180 | - Specifying an `Action` with the legacy return signature of
181 | `func(*cli.Context)` will produce a deprecation message to stderr
182 | - Specifying an `Action` that is not a `func` type will produce a non-zero exit
183 | from `App.Run`
184 | - Specifying an `Action` func that has an invalid (input) signature will
185 | produce a non-zero exit from `App.Run`
186 |
187 | ### Deprecated
188 | -
189 | `cli.App.RunAndExitOnError`, which should now be done by returning an error
190 | that fulfills `cli.ExitCoder` to `cli.App.Run`.
191 | - the legacy signature for
192 | `cli.App.Action` of `func(*cli.Context)`, which should now have a return
193 | signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`.
194 |
195 | ### Fixed
196 | - Added missing `*cli.Context.GlobalFloat64` method
197 |
198 | ## [1.14.0] - 2016-04-03 (backfilled 2016-04-25)
199 | ### Added
200 | - Codebeat badge
201 | - Support for categorization via `CategorizedHelp` and `Categories` on app.
202 |
203 | ### Changed
204 | - Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`.
205 |
206 | ### Fixed
207 | - Ensure version is not shown in help text when `HideVersion` set.
208 |
209 | ## [1.13.0] - 2016-03-06 (backfilled 2016-04-25)
210 | ### Added
211 | - YAML file input support.
212 | - `NArg` method on context.
213 |
214 | ## [1.12.0] - 2016-02-17 (backfilled 2016-04-25)
215 | ### Added
216 | - Custom usage error handling.
217 | - Custom text support in `USAGE` section of help output.
218 | - Improved help messages for empty strings.
219 | - AppVeyor CI configuration.
220 |
221 | ### Changed
222 | - Removed `panic` from default help printer func.
223 | - De-duping and optimizations.
224 |
225 | ### Fixed
226 | - Correctly handle `Before`/`After` at command level when no subcommands.
227 | - Case of literal `-` argument causing flag reordering.
228 | - Environment variable hints on Windows.
229 | - Docs updates.
230 |
231 | ## [1.11.1] - 2015-12-21 (backfilled 2016-04-25)
232 | ### Changed
233 | - Use `path.Base` in `Name` and `HelpName`
234 | - Export `GetName` on flag types.
235 |
236 | ### Fixed
237 | - Flag parsing when skipping is enabled.
238 | - Test output cleanup.
239 | - Move completion check to account for empty input case.
240 |
241 | ## [1.11.0] - 2015-11-15 (backfilled 2016-04-25)
242 | ### Added
243 | - Destination scan support for flags.
244 | - Testing against `tip` in Travis CI config.
245 |
246 | ### Changed
247 | - Go version in Travis CI config.
248 |
249 | ### Fixed
250 | - Removed redundant tests.
251 | - Use correct example naming in tests.
252 |
253 | ## [1.10.2] - 2015-10-29 (backfilled 2016-04-25)
254 | ### Fixed
255 | - Remove unused var in bash completion.
256 |
257 | ## [1.10.1] - 2015-10-21 (backfilled 2016-04-25)
258 | ### Added
259 | - Coverage and reference logos in README.
260 |
261 | ### Fixed
262 | - Use specified values in help and version parsing.
263 | - Only display app version and help message once.
264 |
265 | ## [1.10.0] - 2015-10-06 (backfilled 2016-04-25)
266 | ### Added
267 | - More tests for existing functionality.
268 | - `ArgsUsage` at app and command level for help text flexibility.
269 |
270 | ### Fixed
271 | - Honor `HideHelp` and `HideVersion` in `App.Run`.
272 | - Remove juvenile word from README.
273 |
274 | ## [1.9.0] - 2015-09-08 (backfilled 2016-04-25)
275 | ### Added
276 | - `FullName` on command with accompanying help output update.
277 | - Set default `$PROG` in bash completion.
278 |
279 | ### Changed
280 | - Docs formatting.
281 |
282 | ### Fixed
283 | - Removed self-referential imports in tests.
284 |
285 | ## [1.8.0] - 2015-06-30 (backfilled 2016-04-25)
286 | ### Added
287 | - Support for `Copyright` at app level.
288 | - `Parent` func at context level to walk up context lineage.
289 |
290 | ### Fixed
291 | - Global flag processing at top level.
292 |
293 | ## [1.7.1] - 2015-06-11 (backfilled 2016-04-25)
294 | ### Added
295 | - Aggregate errors from `Before`/`After` funcs.
296 | - Doc comments on flag structs.
297 | - Include non-global flags when checking version and help.
298 | - Travis CI config updates.
299 |
300 | ### Fixed
301 | - Ensure slice type flags have non-nil values.
302 | - Collect global flags from the full command hierarchy.
303 | - Docs prose.
304 |
305 | ## [1.7.0] - 2015-05-03 (backfilled 2016-04-25)
306 | ### Changed
307 | - `HelpPrinter` signature includes output writer.
308 |
309 | ### Fixed
310 | - Specify go 1.1+ in docs.
311 | - Set `Writer` when running command as app.
312 |
313 | ## [1.6.0] - 2015-03-23 (backfilled 2016-04-25)
314 | ### Added
315 | - Multiple author support.
316 | - `NumFlags` at context level.
317 | - `Aliases` at command level.
318 |
319 | ### Deprecated
320 | - `ShortName` at command level.
321 |
322 | ### Fixed
323 | - Subcommand help output.
324 | - Backward compatible support for deprecated `Author` and `Email` fields.
325 | - Docs regarding `Names`/`Aliases`.
326 |
327 | ## [1.5.0] - 2015-02-20 (backfilled 2016-04-25)
328 | ### Added
329 | - `After` hook func support at app and command level.
330 |
331 | ### Fixed
332 | - Use parsed context when running command as subcommand.
333 | - Docs prose.
334 |
335 | ## [1.4.1] - 2015-01-09 (backfilled 2016-04-25)
336 | ### Added
337 | - Support for hiding `-h / --help` flags, but not `help` subcommand.
338 | - Stop flag parsing after `--`.
339 |
340 | ### Fixed
341 | - Help text for generic flags to specify single value.
342 | - Use double quotes in output for defaults.
343 | - Use `ParseInt` instead of `ParseUint` for int environment var values.
344 | - Use `0` as base when parsing int environment var values.
345 |
346 | ## [1.4.0] - 2014-12-12 (backfilled 2016-04-25)
347 | ### Added
348 | - Support for environment variable lookup "cascade".
349 | - Support for `Stdout` on app for output redirection.
350 |
351 | ### Fixed
352 | - Print command help instead of app help in `ShowCommandHelp`.
353 |
354 | ## [1.3.1] - 2014-11-13 (backfilled 2016-04-25)
355 | ### Added
356 | - Docs and example code updates.
357 |
358 | ### Changed
359 | - Default `-v / --version` flag made optional.
360 |
361 | ## [1.3.0] - 2014-08-10 (backfilled 2016-04-25)
362 | ### Added
363 | - `FlagNames` at context level.
364 | - Exposed `VersionPrinter` var for more control over version output.
365 | - Zsh completion hook.
366 | - `AUTHOR` section in default app help template.
367 | - Contribution guidelines.
368 | - `DurationFlag` type.
369 |
370 | ## [1.2.0] - 2014-08-02
371 | ### Added
372 | - Support for environment variable defaults on flags plus tests.
373 |
374 | ## [1.1.0] - 2014-07-15
375 | ### Added
376 | - Bash completion.
377 | - Optional hiding of built-in help command.
378 | - Optional skipping of flag parsing at command level.
379 | - `Author`, `Email`, and `Compiled` metadata on app.
380 | - `Before` hook func support at app and command level.
381 | - `CommandNotFound` func support at app level.
382 | - Command reference available on context.
383 | - `GenericFlag` type.
384 | - `Float64Flag` type.
385 | - `BoolTFlag` type.
386 | - `IsSet` flag helper on context.
387 | - More flag lookup funcs at context level.
388 | - More tests & docs.
389 |
390 | ### Changed
391 | - Help template updates to account for presence/absence of flags.
392 | - Separated subcommand help template.
393 | - Exposed `HelpPrinter` var for more control over help output.
394 |
395 | ## [1.0.0] - 2013-11-01
396 | ### Added
397 | - `help` flag in default app flag set and each command flag set.
398 | - Custom handling of argument parsing errors.
399 | - Command lookup by name at app level.
400 | - `StringSliceFlag` type and supporting `StringSlice` type.
401 | - `IntSliceFlag` type and supporting `IntSlice` type.
402 | - Slice type flag lookups by name at context level.
403 | - Export of app and command help functions.
404 | - More tests & docs.
405 |
406 | ## 0.1.0 - 2013-07-22
407 | ### Added
408 | - Initial implementation.
409 |
410 | [Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD
411 | [1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0
412 | [1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0
413 | [1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0
414 | [1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0
415 | [1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0
416 | [1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0
417 | [1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0
418 | [1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1
419 | [1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0
420 | [1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2
421 | [1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1
422 | [1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0
423 | [1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0
424 | [1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0
425 | [1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1
426 | [1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0
427 | [1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0
428 | [1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0
429 | [1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1
430 | [1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0
431 | [1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1
432 | [1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0
433 | [1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0
434 | [1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0
435 | [1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0
436 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | education, socio-economic status, nationality, personal appearance, race,
10 | religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting Dan Buch at dan@meatballhat.com. All complaints will be
59 | reviewed and investigated and will result in a response that is deemed necessary
60 | and appropriate to the circumstances. The project team is obligated to maintain
61 | confidentiality with regard to the reporter of an incident. Further details of
62 | specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | **NOTE**: the primary maintainer(s) may be found in
4 | [./MAINTAINERS.md](./MAINTAINERS.md).
5 |
6 | Feel free to put up a pull request to fix a bug or maybe add a feature. I will
7 | give it a code review and make sure that it does not break backwards
8 | compatibility. If I or any other collaborators agree that it is in line with
9 | the vision of the project, we will work with you to get the code into
10 | a mergeable state and merge it into the master branch.
11 |
12 | If you have contributed something significant to the project, we will most
13 | likely add you as a collaborator. As a collaborator you are given the ability
14 | to merge others pull requests. It is very important that new code does not
15 | break existing code, so be careful about what code you do choose to merge.
16 |
17 | If you feel like you have contributed to the project but have not yet been added
18 | as a collaborator, we probably forgot to add you :sweat_smile:. Please open an
19 | issue!
20 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Jeremy Saenz & Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/MAINTAINERS.md:
--------------------------------------------------------------------------------
1 | - @meatballhat
2 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/app.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "io/ioutil"
7 | "os"
8 | "path/filepath"
9 | "sort"
10 | "time"
11 | )
12 |
13 | var (
14 | changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"
15 | appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
16 | runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)
17 |
18 | contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
19 |
20 | errInvalidActionType = NewExitError("ERROR invalid Action type. "+
21 | fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
22 | fmt.Sprintf("See %s", appActionDeprecationURL), 2)
23 | )
24 |
25 | // App is the main structure of a cli application. It is recommended that
26 | // an app be created with the cli.NewApp() function
27 | type App struct {
28 | // The name of the program. Defaults to path.Base(os.Args[0])
29 | Name string
30 | // Full name of command for help, defaults to Name
31 | HelpName string
32 | // Description of the program.
33 | Usage string
34 | // Text to override the USAGE section of help
35 | UsageText string
36 | // Description of the program argument format.
37 | ArgsUsage string
38 | // Version of the program
39 | Version string
40 | // Description of the program
41 | Description string
42 | // List of commands to execute
43 | Commands []Command
44 | // List of flags to parse
45 | Flags []Flag
46 | // Boolean to enable bash completion commands
47 | EnableBashCompletion bool
48 | // Boolean to hide built-in help command
49 | HideHelp bool
50 | // Boolean to hide built-in version flag and the VERSION section of help
51 | HideVersion bool
52 | // Populate on app startup, only gettable through method Categories()
53 | categories CommandCategories
54 | // An action to execute when the bash-completion flag is set
55 | BashComplete BashCompleteFunc
56 | // An action to execute before any subcommands are run, but after the context is ready
57 | // If a non-nil error is returned, no subcommands are run
58 | Before BeforeFunc
59 | // An action to execute after any subcommands are run, but after the subcommand has finished
60 | // It is run even if Action() panics
61 | After AfterFunc
62 |
63 | // The action to execute when no subcommands are specified
64 | // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}`
65 | // *Note*: support for the deprecated `Action` signature will be removed in a future version
66 | Action interface{}
67 |
68 | // Execute this function if the proper command cannot be found
69 | CommandNotFound CommandNotFoundFunc
70 | // Execute this function if an usage error occurs
71 | OnUsageError OnUsageErrorFunc
72 | // Compilation date
73 | Compiled time.Time
74 | // List of all authors who contributed
75 | Authors []Author
76 | // Copyright of the binary if any
77 | Copyright string
78 | // Name of Author (Note: Use App.Authors, this is deprecated)
79 | Author string
80 | // Email of Author (Note: Use App.Authors, this is deprecated)
81 | Email string
82 | // Writer writer to write output to
83 | Writer io.Writer
84 | // ErrWriter writes error output
85 | ErrWriter io.Writer
86 | // Execute this function to handle ExitErrors. If not provided, HandleExitCoder is provided to
87 | // function as a default, so this is optional.
88 | ExitErrHandler ExitErrHandlerFunc
89 | // Other custom info
90 | Metadata map[string]interface{}
91 | // Carries a function which returns app specific info.
92 | ExtraInfo func() map[string]string
93 | // CustomAppHelpTemplate the text template for app help topic.
94 | // cli.go uses text/template to render templates. You can
95 | // render custom help text by setting this variable.
96 | CustomAppHelpTemplate string
97 |
98 | didSetup bool
99 | }
100 |
101 | // Tries to find out when this binary was compiled.
102 | // Returns the current time if it fails to find it.
103 | func compileTime() time.Time {
104 | info, err := os.Stat(os.Args[0])
105 | if err != nil {
106 | return time.Now()
107 | }
108 | return info.ModTime()
109 | }
110 |
111 | // NewApp creates a new cli Application with some reasonable defaults for Name,
112 | // Usage, Version and Action.
113 | func NewApp() *App {
114 | return &App{
115 | Name: filepath.Base(os.Args[0]),
116 | HelpName: filepath.Base(os.Args[0]),
117 | Usage: "A new cli application",
118 | UsageText: "",
119 | Version: "0.0.0",
120 | BashComplete: DefaultAppComplete,
121 | Action: helpCommand.Action,
122 | Compiled: compileTime(),
123 | Writer: os.Stdout,
124 | }
125 | }
126 |
127 | // Setup runs initialization code to ensure all data structures are ready for
128 | // `Run` or inspection prior to `Run`. It is internally called by `Run`, but
129 | // will return early if setup has already happened.
130 | func (a *App) Setup() {
131 | if a.didSetup {
132 | return
133 | }
134 |
135 | a.didSetup = true
136 |
137 | if a.Author != "" || a.Email != "" {
138 | a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
139 | }
140 |
141 | newCmds := []Command{}
142 | for _, c := range a.Commands {
143 | if c.HelpName == "" {
144 | c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
145 | }
146 | newCmds = append(newCmds, c)
147 | }
148 | a.Commands = newCmds
149 |
150 | if a.Command(helpCommand.Name) == nil && !a.HideHelp {
151 | a.Commands = append(a.Commands, helpCommand)
152 | if (HelpFlag != BoolFlag{}) {
153 | a.appendFlag(HelpFlag)
154 | }
155 | }
156 |
157 | if !a.HideVersion {
158 | a.appendFlag(VersionFlag)
159 | }
160 |
161 | a.categories = CommandCategories{}
162 | for _, command := range a.Commands {
163 | a.categories = a.categories.AddCommand(command.Category, command)
164 | }
165 | sort.Sort(a.categories)
166 |
167 | if a.Metadata == nil {
168 | a.Metadata = make(map[string]interface{})
169 | }
170 |
171 | if a.Writer == nil {
172 | a.Writer = os.Stdout
173 | }
174 | }
175 |
176 | // Run is the entry point to the cli app. Parses the arguments slice and routes
177 | // to the proper flag/args combination
178 | func (a *App) Run(arguments []string) (err error) {
179 | a.Setup()
180 |
181 | // handle the completion flag separately from the flagset since
182 | // completion could be attempted after a flag, but before its value was put
183 | // on the command line. this causes the flagset to interpret the completion
184 | // flag name as the value of the flag before it which is undesirable
185 | // note that we can only do this because the shell autocomplete function
186 | // always appends the completion flag at the end of the command
187 | shellComplete, arguments := checkShellCompleteFlag(a, arguments)
188 |
189 | // parse flags
190 | set, err := flagSet(a.Name, a.Flags)
191 | if err != nil {
192 | return err
193 | }
194 |
195 | set.SetOutput(ioutil.Discard)
196 | err = set.Parse(arguments[1:])
197 | nerr := normalizeFlags(a.Flags, set)
198 | context := NewContext(a, set, nil)
199 | if nerr != nil {
200 | fmt.Fprintln(a.Writer, nerr)
201 | ShowAppHelp(context)
202 | return nerr
203 | }
204 | context.shellComplete = shellComplete
205 |
206 | if checkCompletions(context) {
207 | return nil
208 | }
209 |
210 | if err != nil {
211 | if a.OnUsageError != nil {
212 | err := a.OnUsageError(context, err, false)
213 | a.handleExitCoder(context, err)
214 | return err
215 | }
216 | fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
217 | ShowAppHelp(context)
218 | return err
219 | }
220 |
221 | if !a.HideHelp && checkHelp(context) {
222 | ShowAppHelp(context)
223 | return nil
224 | }
225 |
226 | if !a.HideVersion && checkVersion(context) {
227 | ShowVersion(context)
228 | return nil
229 | }
230 |
231 | if a.After != nil {
232 | defer func() {
233 | if afterErr := a.After(context); afterErr != nil {
234 | if err != nil {
235 | err = NewMultiError(err, afterErr)
236 | } else {
237 | err = afterErr
238 | }
239 | }
240 | }()
241 | }
242 |
243 | if a.Before != nil {
244 | beforeErr := a.Before(context)
245 | if beforeErr != nil {
246 | fmt.Fprintf(a.Writer, "%v\n\n", beforeErr)
247 | ShowAppHelp(context)
248 | a.handleExitCoder(context, beforeErr)
249 | err = beforeErr
250 | return err
251 | }
252 | }
253 |
254 | args := context.Args()
255 | if args.Present() {
256 | name := args.First()
257 | c := a.Command(name)
258 | if c != nil {
259 | return c.Run(context)
260 | }
261 | }
262 |
263 | if a.Action == nil {
264 | a.Action = helpCommand.Action
265 | }
266 |
267 | // Run default Action
268 | err = HandleAction(a.Action, context)
269 |
270 | a.handleExitCoder(context, err)
271 | return err
272 | }
273 |
274 | // RunAndExitOnError calls .Run() and exits non-zero if an error was returned
275 | //
276 | // Deprecated: instead you should return an error that fulfills cli.ExitCoder
277 | // to cli.App.Run. This will cause the application to exit with the given eror
278 | // code in the cli.ExitCoder
279 | func (a *App) RunAndExitOnError() {
280 | if err := a.Run(os.Args); err != nil {
281 | fmt.Fprintln(a.errWriter(), err)
282 | OsExiter(1)
283 | }
284 | }
285 |
286 | // RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
287 | // generate command-specific flags
288 | func (a *App) RunAsSubcommand(ctx *Context) (err error) {
289 | // append help to commands
290 | if len(a.Commands) > 0 {
291 | if a.Command(helpCommand.Name) == nil && !a.HideHelp {
292 | a.Commands = append(a.Commands, helpCommand)
293 | if (HelpFlag != BoolFlag{}) {
294 | a.appendFlag(HelpFlag)
295 | }
296 | }
297 | }
298 |
299 | newCmds := []Command{}
300 | for _, c := range a.Commands {
301 | if c.HelpName == "" {
302 | c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
303 | }
304 | newCmds = append(newCmds, c)
305 | }
306 | a.Commands = newCmds
307 |
308 | // parse flags
309 | set, err := flagSet(a.Name, a.Flags)
310 | if err != nil {
311 | return err
312 | }
313 |
314 | set.SetOutput(ioutil.Discard)
315 | err = set.Parse(ctx.Args().Tail())
316 | nerr := normalizeFlags(a.Flags, set)
317 | context := NewContext(a, set, ctx)
318 |
319 | if nerr != nil {
320 | fmt.Fprintln(a.Writer, nerr)
321 | fmt.Fprintln(a.Writer)
322 | if len(a.Commands) > 0 {
323 | ShowSubcommandHelp(context)
324 | } else {
325 | ShowCommandHelp(ctx, context.Args().First())
326 | }
327 | return nerr
328 | }
329 |
330 | if checkCompletions(context) {
331 | return nil
332 | }
333 |
334 | if err != nil {
335 | if a.OnUsageError != nil {
336 | err = a.OnUsageError(context, err, true)
337 | a.handleExitCoder(context, err)
338 | return err
339 | }
340 | fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
341 | ShowSubcommandHelp(context)
342 | return err
343 | }
344 |
345 | if len(a.Commands) > 0 {
346 | if checkSubcommandHelp(context) {
347 | return nil
348 | }
349 | } else {
350 | if checkCommandHelp(ctx, context.Args().First()) {
351 | return nil
352 | }
353 | }
354 |
355 | if a.After != nil {
356 | defer func() {
357 | afterErr := a.After(context)
358 | if afterErr != nil {
359 | a.handleExitCoder(context, err)
360 | if err != nil {
361 | err = NewMultiError(err, afterErr)
362 | } else {
363 | err = afterErr
364 | }
365 | }
366 | }()
367 | }
368 |
369 | if a.Before != nil {
370 | beforeErr := a.Before(context)
371 | if beforeErr != nil {
372 | a.handleExitCoder(context, beforeErr)
373 | err = beforeErr
374 | return err
375 | }
376 | }
377 |
378 | args := context.Args()
379 | if args.Present() {
380 | name := args.First()
381 | c := a.Command(name)
382 | if c != nil {
383 | return c.Run(context)
384 | }
385 | }
386 |
387 | // Run default Action
388 | err = HandleAction(a.Action, context)
389 |
390 | a.handleExitCoder(context, err)
391 | return err
392 | }
393 |
394 | // Command returns the named command on App. Returns nil if the command does not exist
395 | func (a *App) Command(name string) *Command {
396 | for _, c := range a.Commands {
397 | if c.HasName(name) {
398 | return &c
399 | }
400 | }
401 |
402 | return nil
403 | }
404 |
405 | // Categories returns a slice containing all the categories with the commands they contain
406 | func (a *App) Categories() CommandCategories {
407 | return a.categories
408 | }
409 |
410 | // VisibleCategories returns a slice of categories and commands that are
411 | // Hidden=false
412 | func (a *App) VisibleCategories() []*CommandCategory {
413 | ret := []*CommandCategory{}
414 | for _, category := range a.categories {
415 | if visible := func() *CommandCategory {
416 | for _, command := range category.Commands {
417 | if !command.Hidden {
418 | return category
419 | }
420 | }
421 | return nil
422 | }(); visible != nil {
423 | ret = append(ret, visible)
424 | }
425 | }
426 | return ret
427 | }
428 |
429 | // VisibleCommands returns a slice of the Commands with Hidden=false
430 | func (a *App) VisibleCommands() []Command {
431 | ret := []Command{}
432 | for _, command := range a.Commands {
433 | if !command.Hidden {
434 | ret = append(ret, command)
435 | }
436 | }
437 | return ret
438 | }
439 |
440 | // VisibleFlags returns a slice of the Flags with Hidden=false
441 | func (a *App) VisibleFlags() []Flag {
442 | return visibleFlags(a.Flags)
443 | }
444 |
445 | func (a *App) hasFlag(flag Flag) bool {
446 | for _, f := range a.Flags {
447 | if flag == f {
448 | return true
449 | }
450 | }
451 |
452 | return false
453 | }
454 |
455 | func (a *App) errWriter() io.Writer {
456 | // When the app ErrWriter is nil use the package level one.
457 | if a.ErrWriter == nil {
458 | return ErrWriter
459 | }
460 |
461 | return a.ErrWriter
462 | }
463 |
464 | func (a *App) appendFlag(flag Flag) {
465 | if !a.hasFlag(flag) {
466 | a.Flags = append(a.Flags, flag)
467 | }
468 | }
469 |
470 | func (a *App) handleExitCoder(context *Context, err error) {
471 | if a.ExitErrHandler != nil {
472 | a.ExitErrHandler(context, err)
473 | } else {
474 | HandleExitCoder(err)
475 | }
476 | }
477 |
478 | // Author represents someone who has contributed to a cli project.
479 | type Author struct {
480 | Name string // The Authors name
481 | Email string // The Authors email
482 | }
483 |
484 | // String makes Author comply to the Stringer interface, to allow an easy print in the templating process
485 | func (a Author) String() string {
486 | e := ""
487 | if a.Email != "" {
488 | e = " <" + a.Email + ">"
489 | }
490 |
491 | return fmt.Sprintf("%v%v", a.Name, e)
492 | }
493 |
494 | // HandleAction attempts to figure out which Action signature was used. If
495 | // it's an ActionFunc or a func with the legacy signature for Action, the func
496 | // is run!
497 | func HandleAction(action interface{}, context *Context) (err error) {
498 | if a, ok := action.(ActionFunc); ok {
499 | return a(context)
500 | } else if a, ok := action.(func(*Context) error); ok {
501 | return a(context)
502 | } else if a, ok := action.(func(*Context)); ok { // deprecated function signature
503 | a(context)
504 | return nil
505 | }
506 |
507 | return errInvalidActionType
508 | }
509 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: "{build}"
2 |
3 | os: Windows Server 2016
4 |
5 | image: Visual Studio 2017
6 |
7 | clone_folder: c:\gopath\src\github.com\urfave\cli
8 |
9 | environment:
10 | GOPATH: C:\gopath
11 | GOVERSION: 1.8.x
12 | PYTHON: C:\Python36-x64
13 | PYTHON_VERSION: 3.6.x
14 | PYTHON_ARCH: 64
15 |
16 | install:
17 | - set PATH=%GOPATH%\bin;C:\go\bin;%PATH%
18 | - go version
19 | - go env
20 | - go get github.com/urfave/gfmrun/...
21 | - go get -v -t ./...
22 |
23 | build_script:
24 | - python runtests vet
25 | - python runtests test
26 | - python runtests gfmrun
27 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/category.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | // CommandCategories is a slice of *CommandCategory.
4 | type CommandCategories []*CommandCategory
5 |
6 | // CommandCategory is a category containing commands.
7 | type CommandCategory struct {
8 | Name string
9 | Commands Commands
10 | }
11 |
12 | func (c CommandCategories) Less(i, j int) bool {
13 | return lexicographicLess(c[i].Name, c[j].Name)
14 | }
15 |
16 | func (c CommandCategories) Len() int {
17 | return len(c)
18 | }
19 |
20 | func (c CommandCategories) Swap(i, j int) {
21 | c[i], c[j] = c[j], c[i]
22 | }
23 |
24 | // AddCommand adds a command to a category.
25 | func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
26 | for _, commandCategory := range c {
27 | if commandCategory.Name == category {
28 | commandCategory.Commands = append(commandCategory.Commands, command)
29 | return c
30 | }
31 | }
32 | return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
33 | }
34 |
35 | // VisibleCommands returns a slice of the Commands with Hidden=false
36 | func (c *CommandCategory) VisibleCommands() []Command {
37 | ret := []Command{}
38 | for _, command := range c.Commands {
39 | if !command.Hidden {
40 | ret = append(ret, command)
41 | }
42 | }
43 | return ret
44 | }
45 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/cli.go:
--------------------------------------------------------------------------------
1 | // Package cli provides a minimal framework for creating and organizing command line
2 | // Go applications. cli is designed to be easy to understand and write, the most simple
3 | // cli application can be written as follows:
4 | // func main() {
5 | // cli.NewApp().Run(os.Args)
6 | // }
7 | //
8 | // Of course this application does not do much, so let's make this an actual application:
9 | // func main() {
10 | // app := cli.NewApp()
11 | // app.Name = "greet"
12 | // app.Usage = "say a greeting"
13 | // app.Action = func(c *cli.Context) error {
14 | // println("Greetings")
15 | // return nil
16 | // }
17 | //
18 | // app.Run(os.Args)
19 | // }
20 | package cli
21 |
22 | //go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go
23 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/command.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "flag"
5 | "fmt"
6 | "io/ioutil"
7 | "sort"
8 | "strings"
9 | )
10 |
11 | // Command is a subcommand for a cli.App.
12 | type Command struct {
13 | // The name of the command
14 | Name string
15 | // short name of the command. Typically one character (deprecated, use `Aliases`)
16 | ShortName string
17 | // A list of aliases for the command
18 | Aliases []string
19 | // A short description of the usage of this command
20 | Usage string
21 | // Custom text to show on USAGE section of help
22 | UsageText string
23 | // A longer explanation of how the command works
24 | Description string
25 | // A short description of the arguments of this command
26 | ArgsUsage string
27 | // The category the command is part of
28 | Category string
29 | // The function to call when checking for bash command completions
30 | BashComplete BashCompleteFunc
31 | // An action to execute before any sub-subcommands are run, but after the context is ready
32 | // If a non-nil error is returned, no sub-subcommands are run
33 | Before BeforeFunc
34 | // An action to execute after any subcommands are run, but after the subcommand has finished
35 | // It is run even if Action() panics
36 | After AfterFunc
37 | // The function to call when this command is invoked
38 | Action interface{}
39 | // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind
40 | // of deprecation period has passed, maybe?
41 |
42 | // Execute this function if a usage error occurs.
43 | OnUsageError OnUsageErrorFunc
44 | // List of child commands
45 | Subcommands Commands
46 | // List of flags to parse
47 | Flags []Flag
48 | // Treat all flags as normal arguments if true
49 | SkipFlagParsing bool
50 | // Skip argument reordering which attempts to move flags before arguments,
51 | // but only works if all flags appear after all arguments. This behavior was
52 | // removed n version 2 since it only works under specific conditions so we
53 | // backport here by exposing it as an option for compatibility.
54 | SkipArgReorder bool
55 | // Boolean to hide built-in help command
56 | HideHelp bool
57 | // Boolean to hide this command from help or completion
58 | Hidden bool
59 | // Boolean to enable short-option handling so user can combine several
60 | // single-character bool arguments into one
61 | // i.e. foobar -o -v -> foobar -ov
62 | UseShortOptionHandling bool
63 |
64 | // Full name of command for help, defaults to full command name, including parent commands.
65 | HelpName string
66 | commandNamePath []string
67 |
68 | // CustomHelpTemplate the text template for the command help topic.
69 | // cli.go uses text/template to render templates. You can
70 | // render custom help text by setting this variable.
71 | CustomHelpTemplate string
72 | }
73 |
74 | type CommandsByName []Command
75 |
76 | func (c CommandsByName) Len() int {
77 | return len(c)
78 | }
79 |
80 | func (c CommandsByName) Less(i, j int) bool {
81 | return lexicographicLess(c[i].Name, c[j].Name)
82 | }
83 |
84 | func (c CommandsByName) Swap(i, j int) {
85 | c[i], c[j] = c[j], c[i]
86 | }
87 |
88 | // FullName returns the full name of the command.
89 | // For subcommands this ensures that parent commands are part of the command path
90 | func (c Command) FullName() string {
91 | if c.commandNamePath == nil {
92 | return c.Name
93 | }
94 | return strings.Join(c.commandNamePath, " ")
95 | }
96 |
97 | // Commands is a slice of Command
98 | type Commands []Command
99 |
100 | // Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
101 | func (c Command) Run(ctx *Context) (err error) {
102 | if len(c.Subcommands) > 0 {
103 | return c.startApp(ctx)
104 | }
105 |
106 | if !c.HideHelp && (HelpFlag != BoolFlag{}) {
107 | // append help to flags
108 | c.Flags = append(
109 | c.Flags,
110 | HelpFlag,
111 | )
112 | }
113 |
114 | set, err := c.parseFlags(ctx.Args().Tail())
115 |
116 | context := NewContext(ctx.App, set, ctx)
117 | context.Command = c
118 | if checkCommandCompletions(context, c.Name) {
119 | return nil
120 | }
121 |
122 | if err != nil {
123 | if c.OnUsageError != nil {
124 | err := c.OnUsageError(context, err, false)
125 | context.App.handleExitCoder(context, err)
126 | return err
127 | }
128 | fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error())
129 | fmt.Fprintln(context.App.Writer)
130 | ShowCommandHelp(context, c.Name)
131 | return err
132 | }
133 |
134 | if checkCommandHelp(context, c.Name) {
135 | return nil
136 | }
137 |
138 | if c.After != nil {
139 | defer func() {
140 | afterErr := c.After(context)
141 | if afterErr != nil {
142 | context.App.handleExitCoder(context, err)
143 | if err != nil {
144 | err = NewMultiError(err, afterErr)
145 | } else {
146 | err = afterErr
147 | }
148 | }
149 | }()
150 | }
151 |
152 | if c.Before != nil {
153 | err = c.Before(context)
154 | if err != nil {
155 | ShowCommandHelp(context, c.Name)
156 | context.App.handleExitCoder(context, err)
157 | return err
158 | }
159 | }
160 |
161 | if c.Action == nil {
162 | c.Action = helpSubcommand.Action
163 | }
164 |
165 | err = HandleAction(c.Action, context)
166 |
167 | if err != nil {
168 | context.App.handleExitCoder(context, err)
169 | }
170 | return err
171 | }
172 |
173 | func (c *Command) parseFlags(args Args) (*flag.FlagSet, error) {
174 | set, err := flagSet(c.Name, c.Flags)
175 | if err != nil {
176 | return nil, err
177 | }
178 | set.SetOutput(ioutil.Discard)
179 |
180 | if c.SkipFlagParsing {
181 | return set, set.Parse(append([]string{"--"}, args...))
182 | }
183 |
184 | if !c.SkipArgReorder {
185 | args = reorderArgs(args)
186 | }
187 |
188 | PARSE:
189 | err = set.Parse(args)
190 | if err != nil {
191 | if c.UseShortOptionHandling {
192 | // To enable short-option handling (e.g., "-it" vs "-i -t")
193 | // we have to iteratively catch parsing errors. This way
194 | // we achieve LR parsing without transforming any arguments.
195 | // Otherwise, there is no way we can discriminate combined
196 | // short options from common arguments that should be left
197 | // untouched.
198 | errStr := err.Error()
199 | trimmed := strings.TrimPrefix(errStr, "flag provided but not defined: ")
200 | if errStr == trimmed {
201 | return nil, err
202 | }
203 | // regenerate the initial args with the split short opts
204 | newArgs := Args{}
205 | for i, arg := range args {
206 | if arg != trimmed {
207 | newArgs = append(newArgs, arg)
208 | continue
209 | }
210 | shortOpts := translateShortOptions(set, Args{trimmed})
211 | if len(shortOpts) == 1 {
212 | return nil, err
213 | }
214 | // add each short option and all remaining arguments
215 | newArgs = append(newArgs, shortOpts...)
216 | newArgs = append(newArgs, args[i+1:]...)
217 | args = newArgs
218 | // now reset the flagset parse again
219 | set, err = flagSet(c.Name, c.Flags)
220 | if err != nil {
221 | return nil, err
222 | }
223 | set.SetOutput(ioutil.Discard)
224 | goto PARSE
225 | }
226 | }
227 | return nil, err
228 | }
229 |
230 | err = normalizeFlags(c.Flags, set)
231 | if err != nil {
232 | return nil, err
233 | }
234 |
235 | return set, nil
236 | }
237 |
238 | // reorderArgs moves all flags before arguments as this is what flag expects
239 | func reorderArgs(args []string) []string {
240 | var nonflags, flags []string
241 |
242 | readFlagValue := false
243 | for i, arg := range args {
244 | if arg == "--" {
245 | nonflags = append(nonflags, args[i:]...)
246 | break
247 | }
248 |
249 | if readFlagValue && !strings.HasPrefix(arg, "-") && !strings.HasPrefix(arg, "--") {
250 | readFlagValue = false
251 | flags = append(flags, arg)
252 | continue
253 | }
254 | readFlagValue = false
255 |
256 | if arg != "-" && strings.HasPrefix(arg, "-") {
257 | flags = append(flags, arg)
258 |
259 | readFlagValue = !strings.Contains(arg, "=")
260 | } else {
261 | nonflags = append(nonflags, arg)
262 | }
263 | }
264 |
265 | return append(flags, nonflags...)
266 | }
267 |
268 | func translateShortOptions(set *flag.FlagSet, flagArgs Args) []string {
269 | allCharsFlags := func (s string) bool {
270 | for i := range s {
271 | f := set.Lookup(string(s[i]))
272 | if f == nil {
273 | return false
274 | }
275 | }
276 | return true
277 | }
278 |
279 | // separate combined flags
280 | var flagArgsSeparated []string
281 | for _, flagArg := range flagArgs {
282 | if strings.HasPrefix(flagArg, "-") && strings.HasPrefix(flagArg, "--") == false && len(flagArg) > 2 {
283 | if !allCharsFlags(flagArg[1:]) {
284 | flagArgsSeparated = append(flagArgsSeparated, flagArg)
285 | continue
286 | }
287 | for _, flagChar := range flagArg[1:] {
288 | flagArgsSeparated = append(flagArgsSeparated, "-"+string(flagChar))
289 | }
290 | } else {
291 | flagArgsSeparated = append(flagArgsSeparated, flagArg)
292 | }
293 | }
294 | return flagArgsSeparated
295 | }
296 |
297 | // Names returns the names including short names and aliases.
298 | func (c Command) Names() []string {
299 | names := []string{c.Name}
300 |
301 | if c.ShortName != "" {
302 | names = append(names, c.ShortName)
303 | }
304 |
305 | return append(names, c.Aliases...)
306 | }
307 |
308 | // HasName returns true if Command.Name or Command.ShortName matches given name
309 | func (c Command) HasName(name string) bool {
310 | for _, n := range c.Names() {
311 | if n == name {
312 | return true
313 | }
314 | }
315 | return false
316 | }
317 |
318 | func (c Command) startApp(ctx *Context) error {
319 | app := NewApp()
320 | app.Metadata = ctx.App.Metadata
321 | // set the name and usage
322 | app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
323 | if c.HelpName == "" {
324 | app.HelpName = c.HelpName
325 | } else {
326 | app.HelpName = app.Name
327 | }
328 |
329 | app.Usage = c.Usage
330 | app.Description = c.Description
331 | app.ArgsUsage = c.ArgsUsage
332 |
333 | // set CommandNotFound
334 | app.CommandNotFound = ctx.App.CommandNotFound
335 | app.CustomAppHelpTemplate = c.CustomHelpTemplate
336 |
337 | // set the flags and commands
338 | app.Commands = c.Subcommands
339 | app.Flags = c.Flags
340 | app.HideHelp = c.HideHelp
341 |
342 | app.Version = ctx.App.Version
343 | app.HideVersion = ctx.App.HideVersion
344 | app.Compiled = ctx.App.Compiled
345 | app.Author = ctx.App.Author
346 | app.Email = ctx.App.Email
347 | app.Writer = ctx.App.Writer
348 | app.ErrWriter = ctx.App.ErrWriter
349 |
350 | app.categories = CommandCategories{}
351 | for _, command := range c.Subcommands {
352 | app.categories = app.categories.AddCommand(command.Category, command)
353 | }
354 |
355 | sort.Sort(app.categories)
356 |
357 | // bash completion
358 | app.EnableBashCompletion = ctx.App.EnableBashCompletion
359 | if c.BashComplete != nil {
360 | app.BashComplete = c.BashComplete
361 | }
362 |
363 | // set the actions
364 | app.Before = c.Before
365 | app.After = c.After
366 | if c.Action != nil {
367 | app.Action = c.Action
368 | } else {
369 | app.Action = helpSubcommand.Action
370 | }
371 | app.OnUsageError = c.OnUsageError
372 |
373 | for index, cc := range app.Commands {
374 | app.Commands[index].commandNamePath = []string{c.Name, cc.Name}
375 | }
376 |
377 | return app.RunAsSubcommand(ctx)
378 | }
379 |
380 | // VisibleFlags returns a slice of the Flags with Hidden=false
381 | func (c Command) VisibleFlags() []Flag {
382 | return visibleFlags(c.Flags)
383 | }
384 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/context.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "errors"
5 | "flag"
6 | "os"
7 | "reflect"
8 | "strings"
9 | "syscall"
10 | )
11 |
12 | // Context is a type that is passed through to
13 | // each Handler action in a cli application. Context
14 | // can be used to retrieve context-specific Args and
15 | // parsed command-line options.
16 | type Context struct {
17 | App *App
18 | Command Command
19 | shellComplete bool
20 | flagSet *flag.FlagSet
21 | setFlags map[string]bool
22 | parentContext *Context
23 | }
24 |
25 | // NewContext creates a new context. For use in when invoking an App or Command action.
26 | func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
27 | c := &Context{App: app, flagSet: set, parentContext: parentCtx}
28 |
29 | if parentCtx != nil {
30 | c.shellComplete = parentCtx.shellComplete
31 | }
32 |
33 | return c
34 | }
35 |
36 | // NumFlags returns the number of flags set
37 | func (c *Context) NumFlags() int {
38 | return c.flagSet.NFlag()
39 | }
40 |
41 | // Set sets a context flag to a value.
42 | func (c *Context) Set(name, value string) error {
43 | c.setFlags = nil
44 | return c.flagSet.Set(name, value)
45 | }
46 |
47 | // GlobalSet sets a context flag to a value on the global flagset
48 | func (c *Context) GlobalSet(name, value string) error {
49 | globalContext(c).setFlags = nil
50 | return globalContext(c).flagSet.Set(name, value)
51 | }
52 |
53 | // IsSet determines if the flag was actually set
54 | func (c *Context) IsSet(name string) bool {
55 | if c.setFlags == nil {
56 | c.setFlags = make(map[string]bool)
57 |
58 | c.flagSet.Visit(func(f *flag.Flag) {
59 | c.setFlags[f.Name] = true
60 | })
61 |
62 | c.flagSet.VisitAll(func(f *flag.Flag) {
63 | if _, ok := c.setFlags[f.Name]; ok {
64 | return
65 | }
66 | c.setFlags[f.Name] = false
67 | })
68 |
69 | // XXX hack to support IsSet for flags with EnvVar
70 | //
71 | // There isn't an easy way to do this with the current implementation since
72 | // whether a flag was set via an environment variable is very difficult to
73 | // determine here. Instead, we intend to introduce a backwards incompatible
74 | // change in version 2 to add `IsSet` to the Flag interface to push the
75 | // responsibility closer to where the information required to determine
76 | // whether a flag is set by non-standard means such as environment
77 | // variables is available.
78 | //
79 | // See https://github.com/urfave/cli/issues/294 for additional discussion
80 | flags := c.Command.Flags
81 | if c.Command.Name == "" { // cannot == Command{} since it contains slice types
82 | if c.App != nil {
83 | flags = c.App.Flags
84 | }
85 | }
86 | for _, f := range flags {
87 | eachName(f.GetName(), func(name string) {
88 | if isSet, ok := c.setFlags[name]; isSet || !ok {
89 | return
90 | }
91 |
92 | val := reflect.ValueOf(f)
93 | if val.Kind() == reflect.Ptr {
94 | val = val.Elem()
95 | }
96 |
97 | filePathValue := val.FieldByName("FilePath")
98 | if filePathValue.IsValid() {
99 | eachName(filePathValue.String(), func(filePath string) {
100 | if _, err := os.Stat(filePath); err == nil {
101 | c.setFlags[name] = true
102 | return
103 | }
104 | })
105 | }
106 |
107 | envVarValue := val.FieldByName("EnvVar")
108 | if envVarValue.IsValid() {
109 | eachName(envVarValue.String(), func(envVar string) {
110 | envVar = strings.TrimSpace(envVar)
111 | if _, ok := syscall.Getenv(envVar); ok {
112 | c.setFlags[name] = true
113 | return
114 | }
115 | })
116 | }
117 | })
118 | }
119 | }
120 |
121 | return c.setFlags[name]
122 | }
123 |
124 | // GlobalIsSet determines if the global flag was actually set
125 | func (c *Context) GlobalIsSet(name string) bool {
126 | ctx := c
127 | if ctx.parentContext != nil {
128 | ctx = ctx.parentContext
129 | }
130 |
131 | for ; ctx != nil; ctx = ctx.parentContext {
132 | if ctx.IsSet(name) {
133 | return true
134 | }
135 | }
136 | return false
137 | }
138 |
139 | // FlagNames returns a slice of flag names used in this context.
140 | func (c *Context) FlagNames() (names []string) {
141 | for _, flag := range c.Command.Flags {
142 | name := strings.Split(flag.GetName(), ",")[0]
143 | if name == "help" {
144 | continue
145 | }
146 | names = append(names, name)
147 | }
148 | return
149 | }
150 |
151 | // GlobalFlagNames returns a slice of global flag names used by the app.
152 | func (c *Context) GlobalFlagNames() (names []string) {
153 | for _, flag := range c.App.Flags {
154 | name := strings.Split(flag.GetName(), ",")[0]
155 | if name == "help" || name == "version" {
156 | continue
157 | }
158 | names = append(names, name)
159 | }
160 | return
161 | }
162 |
163 | // Parent returns the parent context, if any
164 | func (c *Context) Parent() *Context {
165 | return c.parentContext
166 | }
167 |
168 | // value returns the value of the flag coressponding to `name`
169 | func (c *Context) value(name string) interface{} {
170 | return c.flagSet.Lookup(name).Value.(flag.Getter).Get()
171 | }
172 |
173 | // Args contains apps console arguments
174 | type Args []string
175 |
176 | // Args returns the command line arguments associated with the context.
177 | func (c *Context) Args() Args {
178 | args := Args(c.flagSet.Args())
179 | return args
180 | }
181 |
182 | // NArg returns the number of the command line arguments.
183 | func (c *Context) NArg() int {
184 | return len(c.Args())
185 | }
186 |
187 | // Get returns the nth argument, or else a blank string
188 | func (a Args) Get(n int) string {
189 | if len(a) > n {
190 | return a[n]
191 | }
192 | return ""
193 | }
194 |
195 | // First returns the first argument, or else a blank string
196 | func (a Args) First() string {
197 | return a.Get(0)
198 | }
199 |
200 | // Tail returns the rest of the arguments (not the first one)
201 | // or else an empty string slice
202 | func (a Args) Tail() []string {
203 | if len(a) >= 2 {
204 | return []string(a)[1:]
205 | }
206 | return []string{}
207 | }
208 |
209 | // Present checks if there are any arguments present
210 | func (a Args) Present() bool {
211 | return len(a) != 0
212 | }
213 |
214 | // Swap swaps arguments at the given indexes
215 | func (a Args) Swap(from, to int) error {
216 | if from >= len(a) || to >= len(a) {
217 | return errors.New("index out of range")
218 | }
219 | a[from], a[to] = a[to], a[from]
220 | return nil
221 | }
222 |
223 | func globalContext(ctx *Context) *Context {
224 | if ctx == nil {
225 | return nil
226 | }
227 |
228 | for {
229 | if ctx.parentContext == nil {
230 | return ctx
231 | }
232 | ctx = ctx.parentContext
233 | }
234 | }
235 |
236 | func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
237 | if ctx.parentContext != nil {
238 | ctx = ctx.parentContext
239 | }
240 | for ; ctx != nil; ctx = ctx.parentContext {
241 | if f := ctx.flagSet.Lookup(name); f != nil {
242 | return ctx.flagSet
243 | }
244 | }
245 | return nil
246 | }
247 |
248 | func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
249 | switch ff.Value.(type) {
250 | case *StringSlice:
251 | default:
252 | set.Set(name, ff.Value.String())
253 | }
254 | }
255 |
256 | func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
257 | visited := make(map[string]bool)
258 | set.Visit(func(f *flag.Flag) {
259 | visited[f.Name] = true
260 | })
261 | for _, f := range flags {
262 | parts := strings.Split(f.GetName(), ",")
263 | if len(parts) == 1 {
264 | continue
265 | }
266 | var ff *flag.Flag
267 | for _, name := range parts {
268 | name = strings.Trim(name, " ")
269 | if visited[name] {
270 | if ff != nil {
271 | return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name)
272 | }
273 | ff = set.Lookup(name)
274 | }
275 | }
276 | if ff == nil {
277 | continue
278 | }
279 | for _, name := range parts {
280 | name = strings.Trim(name, " ")
281 | if !visited[name] {
282 | copyFlag(name, ff, set)
283 | }
284 | }
285 | }
286 | return nil
287 | }
288 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/errors.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | "strings"
8 | )
9 |
10 | // OsExiter is the function used when the app exits. If not set defaults to os.Exit.
11 | var OsExiter = os.Exit
12 |
13 | // ErrWriter is used to write errors to the user. This can be anything
14 | // implementing the io.Writer interface and defaults to os.Stderr.
15 | var ErrWriter io.Writer = os.Stderr
16 |
17 | // MultiError is an error that wraps multiple errors.
18 | type MultiError struct {
19 | Errors []error
20 | }
21 |
22 | // NewMultiError creates a new MultiError. Pass in one or more errors.
23 | func NewMultiError(err ...error) MultiError {
24 | return MultiError{Errors: err}
25 | }
26 |
27 | // Error implements the error interface.
28 | func (m MultiError) Error() string {
29 | errs := make([]string, len(m.Errors))
30 | for i, err := range m.Errors {
31 | errs[i] = err.Error()
32 | }
33 |
34 | return strings.Join(errs, "\n")
35 | }
36 |
37 | type ErrorFormatter interface {
38 | Format(s fmt.State, verb rune)
39 | }
40 |
41 | // ExitCoder is the interface checked by `App` and `Command` for a custom exit
42 | // code
43 | type ExitCoder interface {
44 | error
45 | ExitCode() int
46 | }
47 |
48 | // ExitError fulfills both the builtin `error` interface and `ExitCoder`
49 | type ExitError struct {
50 | exitCode int
51 | message interface{}
52 | }
53 |
54 | // NewExitError makes a new *ExitError
55 | func NewExitError(message interface{}, exitCode int) *ExitError {
56 | return &ExitError{
57 | exitCode: exitCode,
58 | message: message,
59 | }
60 | }
61 |
62 | // Error returns the string message, fulfilling the interface required by
63 | // `error`
64 | func (ee *ExitError) Error() string {
65 | return fmt.Sprintf("%v", ee.message)
66 | }
67 |
68 | // ExitCode returns the exit code, fulfilling the interface required by
69 | // `ExitCoder`
70 | func (ee *ExitError) ExitCode() int {
71 | return ee.exitCode
72 | }
73 |
74 | // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
75 | // so prints the error to stderr (if it is non-empty) and calls OsExiter with the
76 | // given exit code. If the given error is a MultiError, then this func is
77 | // called on all members of the Errors slice and calls OsExiter with the last exit code.
78 | func HandleExitCoder(err error) {
79 | if err == nil {
80 | return
81 | }
82 |
83 | if exitErr, ok := err.(ExitCoder); ok {
84 | if err.Error() != "" {
85 | if _, ok := exitErr.(ErrorFormatter); ok {
86 | fmt.Fprintf(ErrWriter, "%+v\n", err)
87 | } else {
88 | fmt.Fprintln(ErrWriter, err)
89 | }
90 | }
91 | OsExiter(exitErr.ExitCode())
92 | return
93 | }
94 |
95 | if multiErr, ok := err.(MultiError); ok {
96 | code := handleMultiError(multiErr)
97 | OsExiter(code)
98 | return
99 | }
100 | }
101 |
102 | func handleMultiError(multiErr MultiError) int {
103 | code := 1
104 | for _, merr := range multiErr.Errors {
105 | if multiErr2, ok := merr.(MultiError); ok {
106 | code = handleMultiError(multiErr2)
107 | } else {
108 | fmt.Fprintln(ErrWriter, merr)
109 | if exitErr, ok := merr.(ExitCoder); ok {
110 | code = exitErr.ExitCode()
111 | }
112 | }
113 | }
114 | return code
115 | }
116 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/flag-types.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Bool",
4 | "type": "bool",
5 | "value": false,
6 | "context_default": "false",
7 | "parser": "strconv.ParseBool(f.Value.String())"
8 | },
9 | {
10 | "name": "BoolT",
11 | "type": "bool",
12 | "value": false,
13 | "doctail": " that is true by default",
14 | "context_default": "false",
15 | "parser": "strconv.ParseBool(f.Value.String())"
16 | },
17 | {
18 | "name": "Duration",
19 | "type": "time.Duration",
20 | "doctail": " (see https://golang.org/pkg/time/#ParseDuration)",
21 | "context_default": "0",
22 | "parser": "time.ParseDuration(f.Value.String())"
23 | },
24 | {
25 | "name": "Float64",
26 | "type": "float64",
27 | "context_default": "0",
28 | "parser": "strconv.ParseFloat(f.Value.String(), 64)"
29 | },
30 | {
31 | "name": "Generic",
32 | "type": "Generic",
33 | "dest": false,
34 | "context_default": "nil",
35 | "context_type": "interface{}"
36 | },
37 | {
38 | "name": "Int64",
39 | "type": "int64",
40 | "context_default": "0",
41 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)"
42 | },
43 | {
44 | "name": "Int",
45 | "type": "int",
46 | "context_default": "0",
47 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)",
48 | "parser_cast": "int(parsed)"
49 | },
50 | {
51 | "name": "IntSlice",
52 | "type": "*IntSlice",
53 | "dest": false,
54 | "context_default": "nil",
55 | "context_type": "[]int",
56 | "parser": "(f.Value.(*IntSlice)).Value(), error(nil)"
57 | },
58 | {
59 | "name": "Int64Slice",
60 | "type": "*Int64Slice",
61 | "dest": false,
62 | "context_default": "nil",
63 | "context_type": "[]int64",
64 | "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)"
65 | },
66 | {
67 | "name": "String",
68 | "type": "string",
69 | "context_default": "\"\"",
70 | "parser": "f.Value.String(), error(nil)"
71 | },
72 | {
73 | "name": "StringSlice",
74 | "type": "*StringSlice",
75 | "dest": false,
76 | "context_default": "nil",
77 | "context_type": "[]string",
78 | "parser": "(f.Value.(*StringSlice)).Value(), error(nil)"
79 | },
80 | {
81 | "name": "Uint64",
82 | "type": "uint64",
83 | "context_default": "0",
84 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)"
85 | },
86 | {
87 | "name": "Uint",
88 | "type": "uint",
89 | "context_default": "0",
90 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)",
91 | "parser_cast": "uint(parsed)"
92 | }
93 | ]
94 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/flag_generated.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "flag"
5 | "strconv"
6 | "time"
7 | )
8 |
9 | // WARNING: This file is generated!
10 |
11 | // BoolFlag is a flag with type bool
12 | type BoolFlag struct {
13 | Name string
14 | Usage string
15 | EnvVar string
16 | FilePath string
17 | Hidden bool
18 | Destination *bool
19 | }
20 |
21 | // String returns a readable representation of this value
22 | // (for usage defaults)
23 | func (f BoolFlag) String() string {
24 | return FlagStringer(f)
25 | }
26 |
27 | // GetName returns the name of the flag
28 | func (f BoolFlag) GetName() string {
29 | return f.Name
30 | }
31 |
32 | // Bool looks up the value of a local BoolFlag, returns
33 | // false if not found
34 | func (c *Context) Bool(name string) bool {
35 | return lookupBool(name, c.flagSet)
36 | }
37 |
38 | // GlobalBool looks up the value of a global BoolFlag, returns
39 | // false if not found
40 | func (c *Context) GlobalBool(name string) bool {
41 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
42 | return lookupBool(name, fs)
43 | }
44 | return false
45 | }
46 |
47 | func lookupBool(name string, set *flag.FlagSet) bool {
48 | f := set.Lookup(name)
49 | if f != nil {
50 | parsed, err := strconv.ParseBool(f.Value.String())
51 | if err != nil {
52 | return false
53 | }
54 | return parsed
55 | }
56 | return false
57 | }
58 |
59 | // BoolTFlag is a flag with type bool that is true by default
60 | type BoolTFlag struct {
61 | Name string
62 | Usage string
63 | EnvVar string
64 | FilePath string
65 | Hidden bool
66 | Destination *bool
67 | }
68 |
69 | // String returns a readable representation of this value
70 | // (for usage defaults)
71 | func (f BoolTFlag) String() string {
72 | return FlagStringer(f)
73 | }
74 |
75 | // GetName returns the name of the flag
76 | func (f BoolTFlag) GetName() string {
77 | return f.Name
78 | }
79 |
80 | // BoolT looks up the value of a local BoolTFlag, returns
81 | // false if not found
82 | func (c *Context) BoolT(name string) bool {
83 | return lookupBoolT(name, c.flagSet)
84 | }
85 |
86 | // GlobalBoolT looks up the value of a global BoolTFlag, returns
87 | // false if not found
88 | func (c *Context) GlobalBoolT(name string) bool {
89 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
90 | return lookupBoolT(name, fs)
91 | }
92 | return false
93 | }
94 |
95 | func lookupBoolT(name string, set *flag.FlagSet) bool {
96 | f := set.Lookup(name)
97 | if f != nil {
98 | parsed, err := strconv.ParseBool(f.Value.String())
99 | if err != nil {
100 | return false
101 | }
102 | return parsed
103 | }
104 | return false
105 | }
106 |
107 | // DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration)
108 | type DurationFlag struct {
109 | Name string
110 | Usage string
111 | EnvVar string
112 | FilePath string
113 | Hidden bool
114 | Value time.Duration
115 | Destination *time.Duration
116 | }
117 |
118 | // String returns a readable representation of this value
119 | // (for usage defaults)
120 | func (f DurationFlag) String() string {
121 | return FlagStringer(f)
122 | }
123 |
124 | // GetName returns the name of the flag
125 | func (f DurationFlag) GetName() string {
126 | return f.Name
127 | }
128 |
129 | // Duration looks up the value of a local DurationFlag, returns
130 | // 0 if not found
131 | func (c *Context) Duration(name string) time.Duration {
132 | return lookupDuration(name, c.flagSet)
133 | }
134 |
135 | // GlobalDuration looks up the value of a global DurationFlag, returns
136 | // 0 if not found
137 | func (c *Context) GlobalDuration(name string) time.Duration {
138 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
139 | return lookupDuration(name, fs)
140 | }
141 | return 0
142 | }
143 |
144 | func lookupDuration(name string, set *flag.FlagSet) time.Duration {
145 | f := set.Lookup(name)
146 | if f != nil {
147 | parsed, err := time.ParseDuration(f.Value.String())
148 | if err != nil {
149 | return 0
150 | }
151 | return parsed
152 | }
153 | return 0
154 | }
155 |
156 | // Float64Flag is a flag with type float64
157 | type Float64Flag struct {
158 | Name string
159 | Usage string
160 | EnvVar string
161 | FilePath string
162 | Hidden bool
163 | Value float64
164 | Destination *float64
165 | }
166 |
167 | // String returns a readable representation of this value
168 | // (for usage defaults)
169 | func (f Float64Flag) String() string {
170 | return FlagStringer(f)
171 | }
172 |
173 | // GetName returns the name of the flag
174 | func (f Float64Flag) GetName() string {
175 | return f.Name
176 | }
177 |
178 | // Float64 looks up the value of a local Float64Flag, returns
179 | // 0 if not found
180 | func (c *Context) Float64(name string) float64 {
181 | return lookupFloat64(name, c.flagSet)
182 | }
183 |
184 | // GlobalFloat64 looks up the value of a global Float64Flag, returns
185 | // 0 if not found
186 | func (c *Context) GlobalFloat64(name string) float64 {
187 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
188 | return lookupFloat64(name, fs)
189 | }
190 | return 0
191 | }
192 |
193 | func lookupFloat64(name string, set *flag.FlagSet) float64 {
194 | f := set.Lookup(name)
195 | if f != nil {
196 | parsed, err := strconv.ParseFloat(f.Value.String(), 64)
197 | if err != nil {
198 | return 0
199 | }
200 | return parsed
201 | }
202 | return 0
203 | }
204 |
205 | // GenericFlag is a flag with type Generic
206 | type GenericFlag struct {
207 | Name string
208 | Usage string
209 | EnvVar string
210 | FilePath string
211 | Hidden bool
212 | Value Generic
213 | }
214 |
215 | // String returns a readable representation of this value
216 | // (for usage defaults)
217 | func (f GenericFlag) String() string {
218 | return FlagStringer(f)
219 | }
220 |
221 | // GetName returns the name of the flag
222 | func (f GenericFlag) GetName() string {
223 | return f.Name
224 | }
225 |
226 | // Generic looks up the value of a local GenericFlag, returns
227 | // nil if not found
228 | func (c *Context) Generic(name string) interface{} {
229 | return lookupGeneric(name, c.flagSet)
230 | }
231 |
232 | // GlobalGeneric looks up the value of a global GenericFlag, returns
233 | // nil if not found
234 | func (c *Context) GlobalGeneric(name string) interface{} {
235 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
236 | return lookupGeneric(name, fs)
237 | }
238 | return nil
239 | }
240 |
241 | func lookupGeneric(name string, set *flag.FlagSet) interface{} {
242 | f := set.Lookup(name)
243 | if f != nil {
244 | parsed, err := f.Value, error(nil)
245 | if err != nil {
246 | return nil
247 | }
248 | return parsed
249 | }
250 | return nil
251 | }
252 |
253 | // Int64Flag is a flag with type int64
254 | type Int64Flag struct {
255 | Name string
256 | Usage string
257 | EnvVar string
258 | FilePath string
259 | Hidden bool
260 | Value int64
261 | Destination *int64
262 | }
263 |
264 | // String returns a readable representation of this value
265 | // (for usage defaults)
266 | func (f Int64Flag) String() string {
267 | return FlagStringer(f)
268 | }
269 |
270 | // GetName returns the name of the flag
271 | func (f Int64Flag) GetName() string {
272 | return f.Name
273 | }
274 |
275 | // Int64 looks up the value of a local Int64Flag, returns
276 | // 0 if not found
277 | func (c *Context) Int64(name string) int64 {
278 | return lookupInt64(name, c.flagSet)
279 | }
280 |
281 | // GlobalInt64 looks up the value of a global Int64Flag, returns
282 | // 0 if not found
283 | func (c *Context) GlobalInt64(name string) int64 {
284 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
285 | return lookupInt64(name, fs)
286 | }
287 | return 0
288 | }
289 |
290 | func lookupInt64(name string, set *flag.FlagSet) int64 {
291 | f := set.Lookup(name)
292 | if f != nil {
293 | parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
294 | if err != nil {
295 | return 0
296 | }
297 | return parsed
298 | }
299 | return 0
300 | }
301 |
302 | // IntFlag is a flag with type int
303 | type IntFlag struct {
304 | Name string
305 | Usage string
306 | EnvVar string
307 | FilePath string
308 | Hidden bool
309 | Value int
310 | Destination *int
311 | }
312 |
313 | // String returns a readable representation of this value
314 | // (for usage defaults)
315 | func (f IntFlag) String() string {
316 | return FlagStringer(f)
317 | }
318 |
319 | // GetName returns the name of the flag
320 | func (f IntFlag) GetName() string {
321 | return f.Name
322 | }
323 |
324 | // Int looks up the value of a local IntFlag, returns
325 | // 0 if not found
326 | func (c *Context) Int(name string) int {
327 | return lookupInt(name, c.flagSet)
328 | }
329 |
330 | // GlobalInt looks up the value of a global IntFlag, returns
331 | // 0 if not found
332 | func (c *Context) GlobalInt(name string) int {
333 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
334 | return lookupInt(name, fs)
335 | }
336 | return 0
337 | }
338 |
339 | func lookupInt(name string, set *flag.FlagSet) int {
340 | f := set.Lookup(name)
341 | if f != nil {
342 | parsed, err := strconv.ParseInt(f.Value.String(), 0, 64)
343 | if err != nil {
344 | return 0
345 | }
346 | return int(parsed)
347 | }
348 | return 0
349 | }
350 |
351 | // IntSliceFlag is a flag with type *IntSlice
352 | type IntSliceFlag struct {
353 | Name string
354 | Usage string
355 | EnvVar string
356 | FilePath string
357 | Hidden bool
358 | Value *IntSlice
359 | }
360 |
361 | // String returns a readable representation of this value
362 | // (for usage defaults)
363 | func (f IntSliceFlag) String() string {
364 | return FlagStringer(f)
365 | }
366 |
367 | // GetName returns the name of the flag
368 | func (f IntSliceFlag) GetName() string {
369 | return f.Name
370 | }
371 |
372 | // IntSlice looks up the value of a local IntSliceFlag, returns
373 | // nil if not found
374 | func (c *Context) IntSlice(name string) []int {
375 | return lookupIntSlice(name, c.flagSet)
376 | }
377 |
378 | // GlobalIntSlice looks up the value of a global IntSliceFlag, returns
379 | // nil if not found
380 | func (c *Context) GlobalIntSlice(name string) []int {
381 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
382 | return lookupIntSlice(name, fs)
383 | }
384 | return nil
385 | }
386 |
387 | func lookupIntSlice(name string, set *flag.FlagSet) []int {
388 | f := set.Lookup(name)
389 | if f != nil {
390 | parsed, err := (f.Value.(*IntSlice)).Value(), error(nil)
391 | if err != nil {
392 | return nil
393 | }
394 | return parsed
395 | }
396 | return nil
397 | }
398 |
399 | // Int64SliceFlag is a flag with type *Int64Slice
400 | type Int64SliceFlag struct {
401 | Name string
402 | Usage string
403 | EnvVar string
404 | FilePath string
405 | Hidden bool
406 | Value *Int64Slice
407 | }
408 |
409 | // String returns a readable representation of this value
410 | // (for usage defaults)
411 | func (f Int64SliceFlag) String() string {
412 | return FlagStringer(f)
413 | }
414 |
415 | // GetName returns the name of the flag
416 | func (f Int64SliceFlag) GetName() string {
417 | return f.Name
418 | }
419 |
420 | // Int64Slice looks up the value of a local Int64SliceFlag, returns
421 | // nil if not found
422 | func (c *Context) Int64Slice(name string) []int64 {
423 | return lookupInt64Slice(name, c.flagSet)
424 | }
425 |
426 | // GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns
427 | // nil if not found
428 | func (c *Context) GlobalInt64Slice(name string) []int64 {
429 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
430 | return lookupInt64Slice(name, fs)
431 | }
432 | return nil
433 | }
434 |
435 | func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
436 | f := set.Lookup(name)
437 | if f != nil {
438 | parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil)
439 | if err != nil {
440 | return nil
441 | }
442 | return parsed
443 | }
444 | return nil
445 | }
446 |
447 | // StringFlag is a flag with type string
448 | type StringFlag struct {
449 | Name string
450 | Usage string
451 | EnvVar string
452 | FilePath string
453 | Hidden bool
454 | Value string
455 | Destination *string
456 | }
457 |
458 | // String returns a readable representation of this value
459 | // (for usage defaults)
460 | func (f StringFlag) String() string {
461 | return FlagStringer(f)
462 | }
463 |
464 | // GetName returns the name of the flag
465 | func (f StringFlag) GetName() string {
466 | return f.Name
467 | }
468 |
469 | // String looks up the value of a local StringFlag, returns
470 | // "" if not found
471 | func (c *Context) String(name string) string {
472 | return lookupString(name, c.flagSet)
473 | }
474 |
475 | // GlobalString looks up the value of a global StringFlag, returns
476 | // "" if not found
477 | func (c *Context) GlobalString(name string) string {
478 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
479 | return lookupString(name, fs)
480 | }
481 | return ""
482 | }
483 |
484 | func lookupString(name string, set *flag.FlagSet) string {
485 | f := set.Lookup(name)
486 | if f != nil {
487 | parsed, err := f.Value.String(), error(nil)
488 | if err != nil {
489 | return ""
490 | }
491 | return parsed
492 | }
493 | return ""
494 | }
495 |
496 | // StringSliceFlag is a flag with type *StringSlice
497 | type StringSliceFlag struct {
498 | Name string
499 | Usage string
500 | EnvVar string
501 | FilePath string
502 | Hidden bool
503 | Value *StringSlice
504 | }
505 |
506 | // String returns a readable representation of this value
507 | // (for usage defaults)
508 | func (f StringSliceFlag) String() string {
509 | return FlagStringer(f)
510 | }
511 |
512 | // GetName returns the name of the flag
513 | func (f StringSliceFlag) GetName() string {
514 | return f.Name
515 | }
516 |
517 | // StringSlice looks up the value of a local StringSliceFlag, returns
518 | // nil if not found
519 | func (c *Context) StringSlice(name string) []string {
520 | return lookupStringSlice(name, c.flagSet)
521 | }
522 |
523 | // GlobalStringSlice looks up the value of a global StringSliceFlag, returns
524 | // nil if not found
525 | func (c *Context) GlobalStringSlice(name string) []string {
526 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
527 | return lookupStringSlice(name, fs)
528 | }
529 | return nil
530 | }
531 |
532 | func lookupStringSlice(name string, set *flag.FlagSet) []string {
533 | f := set.Lookup(name)
534 | if f != nil {
535 | parsed, err := (f.Value.(*StringSlice)).Value(), error(nil)
536 | if err != nil {
537 | return nil
538 | }
539 | return parsed
540 | }
541 | return nil
542 | }
543 |
544 | // Uint64Flag is a flag with type uint64
545 | type Uint64Flag struct {
546 | Name string
547 | Usage string
548 | EnvVar string
549 | FilePath string
550 | Hidden bool
551 | Value uint64
552 | Destination *uint64
553 | }
554 |
555 | // String returns a readable representation of this value
556 | // (for usage defaults)
557 | func (f Uint64Flag) String() string {
558 | return FlagStringer(f)
559 | }
560 |
561 | // GetName returns the name of the flag
562 | func (f Uint64Flag) GetName() string {
563 | return f.Name
564 | }
565 |
566 | // Uint64 looks up the value of a local Uint64Flag, returns
567 | // 0 if not found
568 | func (c *Context) Uint64(name string) uint64 {
569 | return lookupUint64(name, c.flagSet)
570 | }
571 |
572 | // GlobalUint64 looks up the value of a global Uint64Flag, returns
573 | // 0 if not found
574 | func (c *Context) GlobalUint64(name string) uint64 {
575 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
576 | return lookupUint64(name, fs)
577 | }
578 | return 0
579 | }
580 |
581 | func lookupUint64(name string, set *flag.FlagSet) uint64 {
582 | f := set.Lookup(name)
583 | if f != nil {
584 | parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
585 | if err != nil {
586 | return 0
587 | }
588 | return parsed
589 | }
590 | return 0
591 | }
592 |
593 | // UintFlag is a flag with type uint
594 | type UintFlag struct {
595 | Name string
596 | Usage string
597 | EnvVar string
598 | FilePath string
599 | Hidden bool
600 | Value uint
601 | Destination *uint
602 | }
603 |
604 | // String returns a readable representation of this value
605 | // (for usage defaults)
606 | func (f UintFlag) String() string {
607 | return FlagStringer(f)
608 | }
609 |
610 | // GetName returns the name of the flag
611 | func (f UintFlag) GetName() string {
612 | return f.Name
613 | }
614 |
615 | // Uint looks up the value of a local UintFlag, returns
616 | // 0 if not found
617 | func (c *Context) Uint(name string) uint {
618 | return lookupUint(name, c.flagSet)
619 | }
620 |
621 | // GlobalUint looks up the value of a global UintFlag, returns
622 | // 0 if not found
623 | func (c *Context) GlobalUint(name string) uint {
624 | if fs := lookupGlobalFlagSet(name, c); fs != nil {
625 | return lookupUint(name, fs)
626 | }
627 | return 0
628 | }
629 |
630 | func lookupUint(name string, set *flag.FlagSet) uint {
631 | f := set.Lookup(name)
632 | if f != nil {
633 | parsed, err := strconv.ParseUint(f.Value.String(), 0, 64)
634 | if err != nil {
635 | return 0
636 | }
637 | return uint(parsed)
638 | }
639 | return 0
640 | }
641 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/funcs.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | // BashCompleteFunc is an action to execute when the bash-completion flag is set
4 | type BashCompleteFunc func(*Context)
5 |
6 | // BeforeFunc is an action to execute before any subcommands are run, but after
7 | // the context is ready if a non-nil error is returned, no subcommands are run
8 | type BeforeFunc func(*Context) error
9 |
10 | // AfterFunc is an action to execute after any subcommands are run, but after the
11 | // subcommand has finished it is run even if Action() panics
12 | type AfterFunc func(*Context) error
13 |
14 | // ActionFunc is the action to execute when no subcommands are specified
15 | type ActionFunc func(*Context) error
16 |
17 | // CommandNotFoundFunc is executed if the proper command cannot be found
18 | type CommandNotFoundFunc func(*Context, string)
19 |
20 | // OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying
21 | // customized usage error messages. This function is able to replace the
22 | // original error messages. If this function is not set, the "Incorrect usage"
23 | // is displayed and the execution is interrupted.
24 | type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error
25 |
26 | // ExitErrHandlerFunc is executed if provided in order to handle ExitError values
27 | // returned by Actions and Before/After functions.
28 | type ExitErrHandlerFunc func(context *Context, err error)
29 |
30 | // FlagStringFunc is used by the help generation to display a flag, which is
31 | // expected to be a single line.
32 | type FlagStringFunc func(Flag) string
33 |
34 | // FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix
35 | // text for a flag's full name.
36 | type FlagNamePrefixFunc func(fullName, placeholder string) string
37 |
38 | // FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help
39 | // with the environment variable details.
40 | type FlagEnvHintFunc func(envVar, str string) string
41 |
42 | // FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help
43 | // with the file path details.
44 | type FlagFileHintFunc func(filePath, str string) string
45 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/generate-flag-types:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """
3 | The flag types that ship with the cli library have many things in common, and
4 | so we can take advantage of the `go generate` command to create much of the
5 | source code from a list of definitions. These definitions attempt to cover
6 | the parts that vary between flag types, and should evolve as needed.
7 |
8 | An example of the minimum definition needed is:
9 |
10 | {
11 | "name": "SomeType",
12 | "type": "sometype",
13 | "context_default": "nil"
14 | }
15 |
16 | In this example, the code generated for the `cli` package will include a type
17 | named `SomeTypeFlag` that is expected to wrap a value of type `sometype`.
18 | Fetching values by name via `*cli.Context` will default to a value of `nil`.
19 |
20 | A more complete, albeit somewhat redundant, example showing all available
21 | definition keys is:
22 |
23 | {
24 | "name": "VeryMuchType",
25 | "type": "*VeryMuchType",
26 | "value": true,
27 | "dest": false,
28 | "doctail": " which really only wraps a []float64, oh well!",
29 | "context_type": "[]float64",
30 | "context_default": "nil",
31 | "parser": "parseVeryMuchType(f.Value.String())",
32 | "parser_cast": "[]float64(parsed)"
33 | }
34 |
35 | The meaning of each field is as follows:
36 |
37 | name (string) - The type "name", which will be suffixed with
38 | `Flag` when generating the type definition
39 | for `cli` and the wrapper type for `altsrc`
40 | type (string) - The type that the generated `Flag` type for `cli`
41 | is expected to "contain" as its `.Value` member
42 | value (bool) - Should the generated `cli` type have a `Value`
43 | member?
44 | dest (bool) - Should the generated `cli` type support a
45 | destination pointer?
46 | doctail (string) - Additional docs for the `cli` flag type comment
47 | context_type (string) - The literal type used in the `*cli.Context`
48 | reader func signature
49 | context_default (string) - The literal value used as the default by the
50 | `*cli.Context` reader funcs when no value is
51 | present
52 | parser (string) - Literal code used to parse the flag `f`,
53 | expected to have a return signature of
54 | (value, error)
55 | parser_cast (string) - Literal code used to cast the `parsed` value
56 | returned from the `parser` code
57 | """
58 |
59 | from __future__ import print_function, unicode_literals
60 |
61 | import argparse
62 | import json
63 | import os
64 | import subprocess
65 | import sys
66 | import tempfile
67 | import textwrap
68 |
69 |
70 | class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter,
71 | argparse.RawDescriptionHelpFormatter):
72 | pass
73 |
74 |
75 | def main(sysargs=sys.argv[:]):
76 | parser = argparse.ArgumentParser(
77 | description='Generate flag type code!',
78 | formatter_class=_FancyFormatter)
79 | parser.add_argument(
80 | 'package',
81 | type=str, default='cli', choices=_WRITEFUNCS.keys(),
82 | help='Package for which flag types will be generated'
83 | )
84 | parser.add_argument(
85 | '-i', '--in-json',
86 | type=argparse.FileType('r'),
87 | default=sys.stdin,
88 | help='Input JSON file which defines each type to be generated'
89 | )
90 | parser.add_argument(
91 | '-o', '--out-go',
92 | type=argparse.FileType('w'),
93 | default=sys.stdout,
94 | help='Output file/stream to which generated source will be written'
95 | )
96 | parser.epilog = __doc__
97 |
98 | args = parser.parse_args(sysargs[1:])
99 | _generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json)
100 | return 0
101 |
102 |
103 | def _generate_flag_types(writefunc, output_go, input_json):
104 | types = json.load(input_json)
105 |
106 | tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False)
107 | writefunc(tmp, types)
108 | tmp.close()
109 |
110 | new_content = subprocess.check_output(
111 | ['goimports', tmp.name]
112 | ).decode('utf-8')
113 |
114 | print(new_content, file=output_go, end='')
115 | output_go.flush()
116 | os.remove(tmp.name)
117 |
118 |
119 | def _set_typedef_defaults(typedef):
120 | typedef.setdefault('doctail', '')
121 | typedef.setdefault('context_type', typedef['type'])
122 | typedef.setdefault('dest', True)
123 | typedef.setdefault('value', True)
124 | typedef.setdefault('parser', 'f.Value, error(nil)')
125 | typedef.setdefault('parser_cast', 'parsed')
126 |
127 |
128 | def _write_cli_flag_types(outfile, types):
129 | _fwrite(outfile, """\
130 | package cli
131 |
132 | // WARNING: This file is generated!
133 |
134 | """)
135 |
136 | for typedef in types:
137 | _set_typedef_defaults(typedef)
138 |
139 | _fwrite(outfile, """\
140 | // {name}Flag is a flag with type {type}{doctail}
141 | type {name}Flag struct {{
142 | Name string
143 | Usage string
144 | EnvVar string
145 | FilePath string
146 | Hidden bool
147 | """.format(**typedef))
148 |
149 | if typedef['value']:
150 | _fwrite(outfile, """\
151 | Value {type}
152 | """.format(**typedef))
153 |
154 | if typedef['dest']:
155 | _fwrite(outfile, """\
156 | Destination *{type}
157 | """.format(**typedef))
158 |
159 | _fwrite(outfile, "\n}\n\n")
160 |
161 | _fwrite(outfile, """\
162 | // String returns a readable representation of this value
163 | // (for usage defaults)
164 | func (f {name}Flag) String() string {{
165 | return FlagStringer(f)
166 | }}
167 |
168 | // GetName returns the name of the flag
169 | func (f {name}Flag) GetName() string {{
170 | return f.Name
171 | }}
172 |
173 | // {name} looks up the value of a local {name}Flag, returns
174 | // {context_default} if not found
175 | func (c *Context) {name}(name string) {context_type} {{
176 | return lookup{name}(name, c.flagSet)
177 | }}
178 |
179 | // Global{name} looks up the value of a global {name}Flag, returns
180 | // {context_default} if not found
181 | func (c *Context) Global{name}(name string) {context_type} {{
182 | if fs := lookupGlobalFlagSet(name, c); fs != nil {{
183 | return lookup{name}(name, fs)
184 | }}
185 | return {context_default}
186 | }}
187 |
188 | func lookup{name}(name string, set *flag.FlagSet) {context_type} {{
189 | f := set.Lookup(name)
190 | if f != nil {{
191 | parsed, err := {parser}
192 | if err != nil {{
193 | return {context_default}
194 | }}
195 | return {parser_cast}
196 | }}
197 | return {context_default}
198 | }}
199 | """.format(**typedef))
200 |
201 |
202 | def _write_altsrc_flag_types(outfile, types):
203 | _fwrite(outfile, """\
204 | package altsrc
205 |
206 | import (
207 | "gopkg.in/urfave/cli.v1"
208 | )
209 |
210 | // WARNING: This file is generated!
211 |
212 | """)
213 |
214 | for typedef in types:
215 | _set_typedef_defaults(typedef)
216 |
217 | _fwrite(outfile, """\
218 | // {name}Flag is the flag type that wraps cli.{name}Flag to allow
219 | // for other values to be specified
220 | type {name}Flag struct {{
221 | cli.{name}Flag
222 | set *flag.FlagSet
223 | }}
224 |
225 | // New{name}Flag creates a new {name}Flag
226 | func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{
227 | return &{name}Flag{{{name}Flag: fl, set: nil}}
228 | }}
229 |
230 | // Apply saves the flagSet for later usage calls, then calls the
231 | // wrapped {name}Flag.Apply
232 | func (f *{name}Flag) Apply(set *flag.FlagSet) {{
233 | f.set = set
234 | f.{name}Flag.Apply(set)
235 | }}
236 |
237 | // ApplyWithError saves the flagSet for later usage calls, then calls the
238 | // wrapped {name}Flag.ApplyWithError
239 | func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{
240 | f.set = set
241 | return f.{name}Flag.ApplyWithError(set)
242 | }}
243 | """.format(**typedef))
244 |
245 |
246 | def _fwrite(outfile, text):
247 | print(textwrap.dedent(text), end='', file=outfile)
248 |
249 |
250 | _WRITEFUNCS = {
251 | 'cli': _write_cli_flag_types,
252 | 'altsrc': _write_altsrc_flag_types
253 | }
254 |
255 | if __name__ == '__main__':
256 | sys.exit(main())
257 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/help.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "os"
7 | "strings"
8 | "text/tabwriter"
9 | "text/template"
10 | )
11 |
12 | // AppHelpTemplate is the text template for the Default help topic.
13 | // cli.go uses text/template to render templates. You can
14 | // render custom help text by setting this variable.
15 | var AppHelpTemplate = `NAME:
16 | {{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
17 |
18 | USAGE:
19 | {{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}}
20 |
21 | VERSION:
22 | {{.Version}}{{end}}{{end}}{{if .Description}}
23 |
24 | DESCRIPTION:
25 | {{.Description}}{{end}}{{if len .Authors}}
26 |
27 | AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
28 | {{range $index, $author := .Authors}}{{if $index}}
29 | {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
30 |
31 | COMMANDS:{{range .VisibleCategories}}{{if .Name}}
32 |
33 | {{.Name}}:{{end}}{{range .VisibleCommands}}
34 | {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
35 |
36 | GLOBAL OPTIONS:
37 | {{range $index, $option := .VisibleFlags}}{{if $index}}
38 | {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}}
39 |
40 | COPYRIGHT:
41 | {{.Copyright}}{{end}}
42 | `
43 |
44 | // CommandHelpTemplate is the text template for the command help topic.
45 | // cli.go uses text/template to render templates. You can
46 | // render custom help text by setting this variable.
47 | var CommandHelpTemplate = `NAME:
48 | {{.HelpName}} - {{.Usage}}
49 |
50 | USAGE:
51 | {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
52 |
53 | CATEGORY:
54 | {{.Category}}{{end}}{{if .Description}}
55 |
56 | DESCRIPTION:
57 | {{.Description}}{{end}}{{if .VisibleFlags}}
58 |
59 | OPTIONS:
60 | {{range .VisibleFlags}}{{.}}
61 | {{end}}{{end}}
62 | `
63 |
64 | // SubcommandHelpTemplate is the text template for the subcommand help topic.
65 | // cli.go uses text/template to render templates. You can
66 | // render custom help text by setting this variable.
67 | var SubcommandHelpTemplate = `NAME:
68 | {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}}
69 |
70 | USAGE:
71 | {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
72 |
73 | COMMANDS:{{range .VisibleCategories}}{{if .Name}}
74 | {{.Name}}:{{end}}{{range .VisibleCommands}}
75 | {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
76 | {{end}}{{if .VisibleFlags}}
77 | OPTIONS:
78 | {{range .VisibleFlags}}{{.}}
79 | {{end}}{{end}}
80 | `
81 |
82 | var helpCommand = Command{
83 | Name: "help",
84 | Aliases: []string{"h"},
85 | Usage: "Shows a list of commands or help for one command",
86 | ArgsUsage: "[command]",
87 | Action: func(c *Context) error {
88 | args := c.Args()
89 | if args.Present() {
90 | return ShowCommandHelp(c, args.First())
91 | }
92 |
93 | ShowAppHelp(c)
94 | return nil
95 | },
96 | }
97 |
98 | var helpSubcommand = Command{
99 | Name: "help",
100 | Aliases: []string{"h"},
101 | Usage: "Shows a list of commands or help for one command",
102 | ArgsUsage: "[command]",
103 | Action: func(c *Context) error {
104 | args := c.Args()
105 | if args.Present() {
106 | return ShowCommandHelp(c, args.First())
107 | }
108 |
109 | return ShowSubcommandHelp(c)
110 | },
111 | }
112 |
113 | // Prints help for the App or Command
114 | type helpPrinter func(w io.Writer, templ string, data interface{})
115 |
116 | // Prints help for the App or Command with custom template function.
117 | type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{})
118 |
119 | // HelpPrinter is a function that writes the help output. If not set a default
120 | // is used. The function signature is:
121 | // func(w io.Writer, templ string, data interface{})
122 | var HelpPrinter helpPrinter = printHelp
123 |
124 | // HelpPrinterCustom is same as HelpPrinter but
125 | // takes a custom function for template function map.
126 | var HelpPrinterCustom helpPrinterCustom = printHelpCustom
127 |
128 | // VersionPrinter prints the version for the App
129 | var VersionPrinter = printVersion
130 |
131 | // ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code.
132 | func ShowAppHelpAndExit(c *Context, exitCode int) {
133 | ShowAppHelp(c)
134 | os.Exit(exitCode)
135 | }
136 |
137 | // ShowAppHelp is an action that displays the help.
138 | func ShowAppHelp(c *Context) (err error) {
139 | if c.App.CustomAppHelpTemplate == "" {
140 | HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
141 | return
142 | }
143 | customAppData := func() map[string]interface{} {
144 | if c.App.ExtraInfo == nil {
145 | return nil
146 | }
147 | return map[string]interface{}{
148 | "ExtraInfo": c.App.ExtraInfo,
149 | }
150 | }
151 | HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData())
152 | return nil
153 | }
154 |
155 | // DefaultAppComplete prints the list of subcommands as the default app completion method
156 | func DefaultAppComplete(c *Context) {
157 | for _, command := range c.App.Commands {
158 | if command.Hidden {
159 | continue
160 | }
161 | if os.Getenv("_CLI_ZSH_AUTOCOMPLETE_HACK") == "1" {
162 | for _, name := range command.Names() {
163 | fmt.Fprintf(c.App.Writer, "%s:%s\n", name, command.Usage)
164 | }
165 | } else {
166 | for _, name := range command.Names() {
167 | fmt.Fprintf(c.App.Writer, "%s\n", name)
168 | }
169 | }
170 | }
171 | }
172 |
173 | // ShowCommandHelpAndExit - exits with code after showing help
174 | func ShowCommandHelpAndExit(c *Context, command string, code int) {
175 | ShowCommandHelp(c, command)
176 | os.Exit(code)
177 | }
178 |
179 | // ShowCommandHelp prints help for the given command
180 | func ShowCommandHelp(ctx *Context, command string) error {
181 | // show the subcommand help for a command with subcommands
182 | if command == "" {
183 | HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App)
184 | return nil
185 | }
186 |
187 | for _, c := range ctx.App.Commands {
188 | if c.HasName(command) {
189 | if c.CustomHelpTemplate != "" {
190 | HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil)
191 | } else {
192 | HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c)
193 | }
194 | return nil
195 | }
196 | }
197 |
198 | if ctx.App.CommandNotFound == nil {
199 | return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3)
200 | }
201 |
202 | ctx.App.CommandNotFound(ctx, command)
203 | return nil
204 | }
205 |
206 | // ShowSubcommandHelp prints help for the given subcommand
207 | func ShowSubcommandHelp(c *Context) error {
208 | return ShowCommandHelp(c, c.Command.Name)
209 | }
210 |
211 | // ShowVersion prints the version number of the App
212 | func ShowVersion(c *Context) {
213 | VersionPrinter(c)
214 | }
215 |
216 | func printVersion(c *Context) {
217 | fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
218 | }
219 |
220 | // ShowCompletions prints the lists of commands within a given context
221 | func ShowCompletions(c *Context) {
222 | a := c.App
223 | if a != nil && a.BashComplete != nil {
224 | a.BashComplete(c)
225 | }
226 | }
227 |
228 | // ShowCommandCompletions prints the custom completions for a given command
229 | func ShowCommandCompletions(ctx *Context, command string) {
230 | c := ctx.App.Command(command)
231 | if c != nil && c.BashComplete != nil {
232 | c.BashComplete(ctx)
233 | }
234 | }
235 |
236 | func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) {
237 | funcMap := template.FuncMap{
238 | "join": strings.Join,
239 | }
240 | if customFunc != nil {
241 | for key, value := range customFunc {
242 | funcMap[key] = value
243 | }
244 | }
245 |
246 | w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
247 | t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
248 | err := t.Execute(w, data)
249 | if err != nil {
250 | // If the writer is closed, t.Execute will fail, and there's nothing
251 | // we can do to recover.
252 | if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
253 | fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
254 | }
255 | return
256 | }
257 | w.Flush()
258 | }
259 |
260 | func printHelp(out io.Writer, templ string, data interface{}) {
261 | printHelpCustom(out, templ, data, nil)
262 | }
263 |
264 | func checkVersion(c *Context) bool {
265 | found := false
266 | if VersionFlag.GetName() != "" {
267 | eachName(VersionFlag.GetName(), func(name string) {
268 | if c.GlobalBool(name) || c.Bool(name) {
269 | found = true
270 | }
271 | })
272 | }
273 | return found
274 | }
275 |
276 | func checkHelp(c *Context) bool {
277 | found := false
278 | if HelpFlag.GetName() != "" {
279 | eachName(HelpFlag.GetName(), func(name string) {
280 | if c.GlobalBool(name) || c.Bool(name) {
281 | found = true
282 | }
283 | })
284 | }
285 | return found
286 | }
287 |
288 | func checkCommandHelp(c *Context, name string) bool {
289 | if c.Bool("h") || c.Bool("help") {
290 | ShowCommandHelp(c, name)
291 | return true
292 | }
293 |
294 | return false
295 | }
296 |
297 | func checkSubcommandHelp(c *Context) bool {
298 | if c.Bool("h") || c.Bool("help") {
299 | ShowSubcommandHelp(c)
300 | return true
301 | }
302 |
303 | return false
304 | }
305 |
306 | func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) {
307 | if !a.EnableBashCompletion {
308 | return false, arguments
309 | }
310 |
311 | pos := len(arguments) - 1
312 | lastArg := arguments[pos]
313 |
314 | if lastArg != "--"+BashCompletionFlag.GetName() {
315 | return false, arguments
316 | }
317 |
318 | return true, arguments[:pos]
319 | }
320 |
321 | func checkCompletions(c *Context) bool {
322 | if !c.shellComplete {
323 | return false
324 | }
325 |
326 | if args := c.Args(); args.Present() {
327 | name := args.First()
328 | if cmd := c.App.Command(name); cmd != nil {
329 | // let the command handle the completion
330 | return false
331 | }
332 | }
333 |
334 | ShowCompletions(c)
335 | return true
336 | }
337 |
338 | func checkCommandCompletions(c *Context, name string) bool {
339 | if !c.shellComplete {
340 | return false
341 | }
342 |
343 | ShowCommandCompletions(c, name)
344 | return true
345 | }
346 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/runtests:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from __future__ import print_function
3 |
4 | import argparse
5 | import os
6 | import sys
7 | import tempfile
8 |
9 | from subprocess import check_call, check_output
10 |
11 |
12 | PACKAGE_NAME = os.environ.get(
13 | 'CLI_PACKAGE_NAME', 'github.com/urfave/cli'
14 | )
15 |
16 |
17 | def main(sysargs=sys.argv[:]):
18 | targets = {
19 | 'vet': _vet,
20 | 'test': _test,
21 | 'gfmrun': _gfmrun,
22 | 'toc': _toc,
23 | 'gen': _gen,
24 | }
25 |
26 | parser = argparse.ArgumentParser()
27 | parser.add_argument(
28 | 'target', nargs='?', choices=tuple(targets.keys()), default='test'
29 | )
30 | args = parser.parse_args(sysargs[1:])
31 |
32 | targets[args.target]()
33 | return 0
34 |
35 |
36 | def _test():
37 | if check_output('go version'.split()).split()[2] < 'go1.2':
38 | _run('go test -v .')
39 | return
40 |
41 | coverprofiles = []
42 | for subpackage in ['', 'altsrc']:
43 | coverprofile = 'cli.coverprofile'
44 | if subpackage != '':
45 | coverprofile = '{}.coverprofile'.format(subpackage)
46 |
47 | coverprofiles.append(coverprofile)
48 |
49 | _run('go test -v'.split() + [
50 | '-coverprofile={}'.format(coverprofile),
51 | ('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/')
52 | ])
53 |
54 | combined_name = _combine_coverprofiles(coverprofiles)
55 | _run('go tool cover -func={}'.format(combined_name))
56 | os.remove(combined_name)
57 |
58 |
59 | def _gfmrun():
60 | go_version = check_output('go version'.split()).split()[2]
61 | if go_version < 'go1.3':
62 | print('runtests: skip on {}'.format(go_version), file=sys.stderr)
63 | return
64 | _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md'])
65 |
66 |
67 | def _vet():
68 | _run('go vet ./...')
69 |
70 |
71 | def _toc():
72 | _run('node_modules/.bin/markdown-toc -i README.md')
73 | _run('git diff --exit-code')
74 |
75 |
76 | def _gen():
77 | go_version = check_output('go version'.split()).split()[2]
78 | if go_version < 'go1.5':
79 | print('runtests: skip on {}'.format(go_version), file=sys.stderr)
80 | return
81 |
82 | _run('go generate ./...')
83 | _run('git diff --exit-code')
84 |
85 |
86 | def _run(command):
87 | if hasattr(command, 'split'):
88 | command = command.split()
89 | print('runtests: {}'.format(' '.join(command)), file=sys.stderr)
90 | check_call(command)
91 |
92 |
93 | def _gfmrun_count():
94 | with open('README.md') as infile:
95 | lines = infile.read().splitlines()
96 | return len(filter(_is_go_runnable, lines))
97 |
98 |
99 | def _is_go_runnable(line):
100 | return line.startswith('package main')
101 |
102 |
103 | def _combine_coverprofiles(coverprofiles):
104 | combined = tempfile.NamedTemporaryFile(
105 | suffix='.coverprofile', delete=False
106 | )
107 | combined.write('mode: set\n')
108 |
109 | for coverprofile in coverprofiles:
110 | with open(coverprofile, 'r') as infile:
111 | for line in infile.readlines():
112 | if not line.startswith('mode: '):
113 | combined.write(line)
114 |
115 | combined.flush()
116 | name = combined.name
117 | combined.close()
118 | return name
119 |
120 |
121 | if __name__ == '__main__':
122 | sys.exit(main())
123 |
--------------------------------------------------------------------------------
/vendor/github.com/urfave/cli/sort.go:
--------------------------------------------------------------------------------
1 | package cli
2 |
3 | import "unicode"
4 |
5 | // lexicographicLess compares strings alphabetically considering case.
6 | func lexicographicLess(i, j string) bool {
7 | iRunes := []rune(i)
8 | jRunes := []rune(j)
9 |
10 | lenShared := len(iRunes)
11 | if lenShared > len(jRunes) {
12 | lenShared = len(jRunes)
13 | }
14 |
15 | for index := 0; index < lenShared; index++ {
16 | ir := iRunes[index]
17 | jr := jRunes[index]
18 |
19 | if lir, ljr := unicode.ToLower(ir), unicode.ToLower(jr); lir != ljr {
20 | return lir < ljr
21 | }
22 |
23 | if ir != jr {
24 | return ir < jr
25 | }
26 | }
27 |
28 | return i < j
29 | }
30 |
--------------------------------------------------------------------------------
/vendor/vendor.json:
--------------------------------------------------------------------------------
1 | {
2 | "comment": "",
3 | "ignore": "test",
4 | "package": [
5 | {
6 | "path": "github.com/go-chi/ch",
7 | "revision": ""
8 | },
9 | {
10 | "checksumSHA1": "Pxx+8cipatmpykEo9DpKFqBIOkk=",
11 | "path": "github.com/go-chi/chi",
12 | "revision": "1a6bb108ccf279c8dac6f9bad857d773b4f9b421",
13 | "revisionTime": "2019-01-17T22:35:40Z"
14 | },
15 | {
16 | "checksumSHA1": "n9ry/OHiteTTjZOeJHTrEwRSnms=",
17 | "path": "github.com/go-chi/cors",
18 | "revision": "07727c846d14299758e54a275dd8c81353c01960",
19 | "revisionTime": "2018-08-16T15:23:45Z"
20 | },
21 | {
22 | "path": "github.com/urfave/cl",
23 | "revision": ""
24 | },
25 | {
26 | "checksumSHA1": "KRlS8eQZGK1oYVCOkIvcMDXabxk=",
27 | "path": "github.com/urfave/cli",
28 | "revision": "b67dcf995b6a7b7f14fad5fcb7cc5441b05e814b",
29 | "revisionTime": "2018-10-29T21:32:00Z"
30 | }
31 | ],
32 | "rootPath": "github.com/luojilab/json2graphql"
33 | }
34 |
--------------------------------------------------------------------------------