├── .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 | # chi 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 | --------------------------------------------------------------------------------