1
0
Fork 0
forked from External/ergo

fix #782 (bring vendor into the main tree)

This commit is contained in:
Shivaram Lingamneni 2020-02-12 13:19:23 -05:00
parent 702c7b1e7c
commit d0aa7cc860
616 changed files with 359667 additions and 31 deletions

25
vendor/github.com/docopt/docopt-go/.gitignore generated vendored Normal file
View file

@ -0,0 +1,25 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
# coverage droppings
profile.cov

32
vendor/github.com/docopt/docopt-go/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,32 @@
# Travis CI (http://travis-ci.org/) is a continuous integration
# service for open source projects. This file configures it
# to run unit tests for docopt-go.
language: go
go:
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- tip
matrix:
fast_finish: true
before_install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
install:
- go get -d -v ./... && go build -v ./...
script:
- go vet -x ./...
- go test -v ./...
- go test -covermode=count -coverprofile=profile.cov .
after_script:
- $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci

21
vendor/github.com/docopt/docopt-go/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013 Keith Batten
Copyright (c) 2016 David Irvine
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

116
vendor/github.com/docopt/docopt-go/README.md generated vendored Normal file
View file

@ -0,0 +1,116 @@
docopt-go
=========
[![Build Status](https://travis-ci.org/docopt/docopt.go.svg?branch=master)](https://travis-ci.org/docopt/docopt.go)
[![Coverage Status](https://coveralls.io/repos/github/docopt/docopt.go/badge.svg)](https://coveralls.io/github/docopt/docopt.go)
[![GoDoc](https://godoc.org/github.com/docopt/docopt.go?status.svg)](https://godoc.org/github.com/docopt/docopt.go)
An implementation of [docopt](http://docopt.org/) in the [Go](http://golang.org/) programming language.
**docopt** helps you create *beautiful* command-line interfaces easily:
```go
package main
import (
"fmt"
"github.com/docopt/docopt-go"
)
func main() {
usage := `Naval Fate.
Usage:
naval_fate ship new <name>...
naval_fate ship <name> move <x> <y> [--speed=<kn>]
naval_fate ship shoot <x> <y>
naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
naval_fate -h | --help
naval_fate --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.`
arguments, _ := docopt.ParseDoc(usage)
fmt.Println(arguments)
}
```
**docopt** parses command-line arguments based on a help message. Don't write parser code: a good help message already has all the necessary information in it.
## Installation
⚠ Use the alias "docopt-go". To use docopt in your Go code:
```go
import "github.com/docopt/docopt-go"
```
To install docopt in your `$GOPATH`:
```console
$ go get github.com/docopt/docopt-go
```
## API
Given a conventional command-line help message, docopt processes the arguments. See https://github.com/docopt/docopt#help-message-format for a description of the help message format.
This package exposes three different APIs, depending on the level of control required. The first, simplest way to parse your docopt usage is to just call:
```go
docopt.ParseDoc(usage)
```
This will use `os.Args[1:]` as the argv slice, and use the default parser options. If you want to provide your own version string and args, then use:
```go
docopt.ParseArgs(usage, argv, "1.2.3")
```
If the last parameter (version) is a non-empty string, it will be printed when `--version` is given in the argv slice. Finally, we can instantiate our own `docopt.Parser` which gives us control over how things like help messages are printed and whether to exit after displaying usage messages, etc.
```go
parser := &docopt.Parser{
HelpHandler: docopt.PrintHelpOnly,
OptionsFirst: true,
}
opts, err := parser.ParseArgs(usage, argv, "")
```
In particular, setting your own custom `HelpHandler` function makes unit testing your own docs with example command line invocations much more enjoyable.
All three of these return a map of option names to the values parsed from argv, and an error or nil. You can get the values using the helpers, or just treat it as a regular map:
```go
flag, _ := opts.Bool("--flag")
secs, _ := opts.Int("<seconds>")
```
Additionally, you can `Bind` these to a struct, assigning option values to the
exported fields of that struct, all at once.
```go
var config struct {
Command string `docopt:"<cmd>"`
Tries int `docopt:"-n"`
Force bool // Gets the value of --force
}
opts.Bind(&config)
```
More documentation is available at [godoc.org](https://godoc.org/github.com/docopt/docopt-go).
## Unit Testing
Unit testing your own usage docs is recommended, so you can be sure that for a given command line invocation, the expected options are set. An example of how to do this is [in the examples folder](examples/unit_test/unit_test.go).
## Tests
All tests from the Python version are implemented and passing at [Travis CI](https://travis-ci.org/docopt/docopt-go). New language-agnostic tests have been added to [test_golang.docopt](test_golang.docopt).
To run tests for docopt-go, use `go test`.

49
vendor/github.com/docopt/docopt-go/doc.go generated vendored Normal file
View file

@ -0,0 +1,49 @@
/*
Package docopt parses command-line arguments based on a help message.
Given a conventional command-line help message, docopt processes the arguments.
See https://github.com/docopt/docopt#help-message-format for a description of
the help message format.
This package exposes three different APIs, depending on the level of control
required. The first, simplest way to parse your docopt usage is to just call:
docopt.ParseDoc(usage)
This will use os.Args[1:] as the argv slice, and use the default parser
options. If you want to provide your own version string and args, then use:
docopt.ParseArgs(usage, argv, "1.2.3")
If the last parameter (version) is a non-empty string, it will be printed when
--version is given in the argv slice. Finally, we can instantiate our own
docopt.Parser which gives us control over how things like help messages are
printed and whether to exit after displaying usage messages, etc.
parser := &docopt.Parser{
HelpHandler: docopt.PrintHelpOnly,
OptionsFirst: true,
}
opts, err := parser.ParseArgs(usage, argv, "")
In particular, setting your own custom HelpHandler function makes unit testing
your own docs with example command line invocations much more enjoyable.
All three of these return a map of option names to the values parsed from argv,
and an error or nil. You can get the values using the helpers, or just treat it
as a regular map:
flag, _ := opts.Bool("--flag")
secs, _ := opts.Int("<seconds>")
Additionally, you can `Bind` these to a struct, assigning option values to the
exported fields of that struct, all at once.
var config struct {
Command string `docopt:"<cmd>"`
Tries int `docopt:"-n"`
Force bool // Gets the value of --force
}
opts.Bind(&config)
*/
package docopt

575
vendor/github.com/docopt/docopt-go/docopt.go generated vendored Normal file
View file

@ -0,0 +1,575 @@
// Licensed under terms of MIT license (see LICENSE-MIT)
// Copyright (c) 2013 Keith Batten, kbatten@gmail.com
// Copyright (c) 2016 David Irvine
package docopt
import (
"fmt"
"os"
"regexp"
"strings"
)
type Parser struct {
// HelpHandler is called when we encounter bad user input, or when the user
// asks for help.
// By default, this calls os.Exit(0) if it handled a built-in option such
// as -h, --help or --version. If the user errored with a wrong command or
// options, we exit with a return code of 1.
HelpHandler func(err error, usage string)
// OptionsFirst requires that option flags always come before positional
// arguments; otherwise they can overlap.
OptionsFirst bool
// SkipHelpFlags tells the parser not to look for -h and --help flags and
// call the HelpHandler.
SkipHelpFlags bool
}
var PrintHelpAndExit = func(err error, usage string) {
if err != nil {
fmt.Fprintln(os.Stderr, usage)
os.Exit(1)
} else {
fmt.Println(usage)
os.Exit(0)
}
}
var PrintHelpOnly = func(err error, usage string) {
if err != nil {
fmt.Fprintln(os.Stderr, usage)
} else {
fmt.Println(usage)
}
}
var NoHelpHandler = func(err error, usage string) {}
var DefaultParser = &Parser{
HelpHandler: PrintHelpAndExit,
OptionsFirst: false,
SkipHelpFlags: false,
}
// ParseDoc parses os.Args[1:] based on the interface described in doc, using the default parser options.
func ParseDoc(doc string) (Opts, error) {
return ParseArgs(doc, nil, "")
}
// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
// string, then this will be displayed when the --version flag is found. This method uses the default parser options.
func ParseArgs(doc string, argv []string, version string) (Opts, error) {
return DefaultParser.ParseArgs(doc, argv, version)
}
// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
// string, then this will be displayed when the --version flag is found.
func (p *Parser) ParseArgs(doc string, argv []string, version string) (Opts, error) {
return p.parse(doc, argv, version)
}
// Deprecated: Parse is provided for backward compatibility with the original docopt.go package.
// Please rather make use of ParseDoc, ParseArgs, or use your own custom Parser.
func Parse(doc string, argv []string, help bool, version string, optionsFirst bool, exit ...bool) (map[string]interface{}, error) {
exitOk := true
if len(exit) > 0 {
exitOk = exit[0]
}
p := &Parser{
OptionsFirst: optionsFirst,
SkipHelpFlags: !help,
}
if exitOk {
p.HelpHandler = PrintHelpAndExit
} else {
p.HelpHandler = PrintHelpOnly
}
return p.parse(doc, argv, version)
}
func (p *Parser) parse(doc string, argv []string, version string) (map[string]interface{}, error) {
if argv == nil {
argv = os.Args[1:]
}
if p.HelpHandler == nil {
p.HelpHandler = DefaultParser.HelpHandler
}
args, output, err := parse(doc, argv, !p.SkipHelpFlags, version, p.OptionsFirst)
if _, ok := err.(*UserError); ok {
// the user gave us bad input
p.HelpHandler(err, output)
} else if len(output) > 0 && err == nil {
// the user asked for help or --version
p.HelpHandler(err, output)
}
return args, err
}
// -----------------------------------------------------------------------------
// parse and return a map of args, output and all errors
func parse(doc string, argv []string, help bool, version string, optionsFirst bool) (args map[string]interface{}, output string, err error) {
if argv == nil && len(os.Args) > 1 {
argv = os.Args[1:]
}
usageSections := parseSection("usage:", doc)
if len(usageSections) == 0 {
err = newLanguageError("\"usage:\" (case-insensitive) not found.")
return
}
if len(usageSections) > 1 {
err = newLanguageError("More than one \"usage:\" (case-insensitive).")
return
}
usage := usageSections[0]
options := parseDefaults(doc)
formal, err := formalUsage(usage)
if err != nil {
output = handleError(err, usage)
return
}
pat, err := parsePattern(formal, &options)
if err != nil {
output = handleError(err, usage)
return
}
patternArgv, err := parseArgv(newTokenList(argv, errorUser), &options, optionsFirst)
if err != nil {
output = handleError(err, usage)
return
}
patFlat, err := pat.flat(patternOption)
if err != nil {
output = handleError(err, usage)
return
}
patternOptions := patFlat.unique()
patFlat, err = pat.flat(patternOptionSSHORTCUT)
if err != nil {
output = handleError(err, usage)
return
}
for _, optionsShortcut := range patFlat {
docOptions := parseDefaults(doc)
optionsShortcut.children = docOptions.unique().diff(patternOptions)
}
if output = extras(help, version, patternArgv, doc); len(output) > 0 {
return
}
err = pat.fix()
if err != nil {
output = handleError(err, usage)
return
}
matched, left, collected := pat.match(&patternArgv, nil)
if matched && len(*left) == 0 {
patFlat, err = pat.flat(patternDefault)
if err != nil {
output = handleError(err, usage)
return
}
args = append(patFlat, *collected...).dictionary()
return
}
err = newUserError("")
output = handleError(err, usage)
return
}
func handleError(err error, usage string) string {
if _, ok := err.(*UserError); ok {
return strings.TrimSpace(fmt.Sprintf("%s\n%s", err, usage))
}
return ""
}
func parseSection(name, source string) []string {
p := regexp.MustCompile(`(?im)^([^\n]*` + name + `[^\n]*\n?(?:[ \t].*?(?:\n|$))*)`)
s := p.FindAllString(source, -1)
if s == nil {
s = []string{}
}
for i, v := range s {
s[i] = strings.TrimSpace(v)
}
return s
}
func parseDefaults(doc string) patternList {
defaults := patternList{}
p := regexp.MustCompile(`\n[ \t]*(-\S+?)`)
for _, s := range parseSection("options:", doc) {
// FIXME corner case "bla: options: --foo"
_, _, s = stringPartition(s, ":") // get rid of "options:"
split := p.Split("\n"+s, -1)[1:]
match := p.FindAllStringSubmatch("\n"+s, -1)
for i := range split {
optionDescription := match[i][1] + split[i]
if strings.HasPrefix(optionDescription, "-") {
defaults = append(defaults, parseOption(optionDescription))
}
}
}
return defaults
}
func parsePattern(source string, options *patternList) (*pattern, error) {
tokens := tokenListFromPattern(source)
result, err := parseExpr(tokens, options)
if err != nil {
return nil, err
}
if tokens.current() != nil {
return nil, tokens.errorFunc("unexpected ending: %s" + strings.Join(tokens.tokens, " "))
}
return newRequired(result...), nil
}
func parseArgv(tokens *tokenList, options *patternList, optionsFirst bool) (patternList, error) {
/*
Parse command-line argument vector.
If options_first:
argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
else:
argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
*/
parsed := patternList{}
for tokens.current() != nil {
if tokens.current().eq("--") {
for _, v := range tokens.tokens {
parsed = append(parsed, newArgument("", v))
}
return parsed, nil
} else if tokens.current().hasPrefix("--") {
pl, err := parseLong(tokens, options)
if err != nil {
return nil, err
}
parsed = append(parsed, pl...)
} else if tokens.current().hasPrefix("-") && !tokens.current().eq("-") {
ps, err := parseShorts(tokens, options)
if err != nil {
return nil, err
}
parsed = append(parsed, ps...)
} else if optionsFirst {
for _, v := range tokens.tokens {
parsed = append(parsed, newArgument("", v))
}
return parsed, nil
} else {
parsed = append(parsed, newArgument("", tokens.move().String()))
}
}
return parsed, nil
}
func parseOption(optionDescription string) *pattern {
optionDescription = strings.TrimSpace(optionDescription)
options, _, description := stringPartition(optionDescription, " ")
options = strings.Replace(options, ",", " ", -1)
options = strings.Replace(options, "=", " ", -1)
short := ""
long := ""
argcount := 0
var value interface{}
value = false
reDefault := regexp.MustCompile(`(?i)\[default: (.*)\]`)
for _, s := range strings.Fields(options) {
if strings.HasPrefix(s, "--") {
long = s
} else if strings.HasPrefix(s, "-") {
short = s
} else {
argcount = 1
}
if argcount > 0 {
matched := reDefault.FindAllStringSubmatch(description, -1)
if len(matched) > 0 {
value = matched[0][1]
} else {
value = nil
}
}
}
return newOption(short, long, argcount, value)
}
func parseExpr(tokens *tokenList, options *patternList) (patternList, error) {
// expr ::= seq ( '|' seq )* ;
seq, err := parseSeq(tokens, options)
if err != nil {
return nil, err
}
if !tokens.current().eq("|") {
return seq, nil
}
var result patternList
if len(seq) > 1 {
result = patternList{newRequired(seq...)}
} else {
result = seq
}
for tokens.current().eq("|") {
tokens.move()
seq, err = parseSeq(tokens, options)
if err != nil {
return nil, err
}
if len(seq) > 1 {
result = append(result, newRequired(seq...))
} else {
result = append(result, seq...)
}
}
if len(result) > 1 {
return patternList{newEither(result...)}, nil
}
return result, nil
}
func parseSeq(tokens *tokenList, options *patternList) (patternList, error) {
// seq ::= ( atom [ '...' ] )* ;
result := patternList{}
for !tokens.current().match(true, "]", ")", "|") {
atom, err := parseAtom(tokens, options)
if err != nil {
return nil, err
}
if tokens.current().eq("...") {
atom = patternList{newOneOrMore(atom...)}
tokens.move()
}
result = append(result, atom...)
}
return result, nil
}
func parseAtom(tokens *tokenList, options *patternList) (patternList, error) {
// atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ;
tok := tokens.current()
result := patternList{}
if tokens.current().match(false, "(", "[") {
tokens.move()
var matching string
pl, err := parseExpr(tokens, options)
if err != nil {
return nil, err
}
if tok.eq("(") {
matching = ")"
result = patternList{newRequired(pl...)}
} else if tok.eq("[") {
matching = "]"
result = patternList{newOptional(pl...)}
}
moved := tokens.move()
if !moved.eq(matching) {
return nil, tokens.errorFunc("unmatched '%s', expected: '%s' got: '%s'", tok, matching, moved)
}
return result, nil
} else if tok.eq("options") {
tokens.move()
return patternList{newOptionsShortcut()}, nil
} else if tok.hasPrefix("--") && !tok.eq("--") {
return parseLong(tokens, options)
} else if tok.hasPrefix("-") && !tok.eq("-") && !tok.eq("--") {
return parseShorts(tokens, options)
} else if tok.hasPrefix("<") && tok.hasSuffix(">") || tok.isUpper() {
return patternList{newArgument(tokens.move().String(), nil)}, nil
}
return patternList{newCommand(tokens.move().String(), false)}, nil
}
func parseLong(tokens *tokenList, options *patternList) (patternList, error) {
// long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
long, eq, v := stringPartition(tokens.move().String(), "=")
var value interface{}
var opt *pattern
if eq == "" && v == "" {
value = nil
} else {
value = v
}
if !strings.HasPrefix(long, "--") {
return nil, newError("long option '%s' doesn't start with --", long)
}
similar := patternList{}
for _, o := range *options {
if o.long == long {
similar = append(similar, o)
}
}
if tokens.err == errorUser && len(similar) == 0 { // if no exact match
similar = patternList{}
for _, o := range *options {
if strings.HasPrefix(o.long, long) {
similar = append(similar, o)
}
}
}
if len(similar) > 1 { // might be simply specified ambiguously 2+ times?
similarLong := make([]string, len(similar))
for i, s := range similar {
similarLong[i] = s.long
}
return nil, tokens.errorFunc("%s is not a unique prefix: %s?", long, strings.Join(similarLong, ", "))
} else if len(similar) < 1 {
argcount := 0
if eq == "=" {
argcount = 1
}
opt = newOption("", long, argcount, false)
*options = append(*options, opt)
if tokens.err == errorUser {
var val interface{}
if argcount > 0 {
val = value
} else {
val = true
}
opt = newOption("", long, argcount, val)
}
} else {
opt = newOption(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value)
if opt.argcount == 0 {
if value != nil {
return nil, tokens.errorFunc("%s must not have an argument", opt.long)
}
} else {
if value == nil {
if tokens.current().match(true, "--") {
return nil, tokens.errorFunc("%s requires argument", opt.long)
}
moved := tokens.move()
if moved != nil {
value = moved.String() // only set as string if not nil
}
}
}
if tokens.err == errorUser {
if value != nil {
opt.value = value
} else {
opt.value = true
}
}
}
return patternList{opt}, nil
}
func parseShorts(tokens *tokenList, options *patternList) (patternList, error) {
// shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;
tok := tokens.move()
if !tok.hasPrefix("-") || tok.hasPrefix("--") {
return nil, newError("short option '%s' doesn't start with -", tok)
}
left := strings.TrimLeft(tok.String(), "-")
parsed := patternList{}
for left != "" {
var opt *pattern
short := "-" + left[0:1]
left = left[1:]
similar := patternList{}
for _, o := range *options {
if o.short == short {
similar = append(similar, o)
}
}
if len(similar) > 1 {
return nil, tokens.errorFunc("%s is specified ambiguously %d times", short, len(similar))
} else if len(similar) < 1 {
opt = newOption(short, "", 0, false)
*options = append(*options, opt)
if tokens.err == errorUser {
opt = newOption(short, "", 0, true)
}
} else { // why copying is necessary here?
opt = newOption(short, similar[0].long, similar[0].argcount, similar[0].value)
var value interface{}
if opt.argcount > 0 {
if left == "" {
if tokens.current().match(true, "--") {
return nil, tokens.errorFunc("%s requires argument", short)
}
value = tokens.move().String()
} else {
value = left
left = ""
}
}
if tokens.err == errorUser {
if value != nil {
opt.value = value
} else {
opt.value = true
}
}
}
parsed = append(parsed, opt)
}
return parsed, nil
}
func formalUsage(section string) (string, error) {
_, _, section = stringPartition(section, ":") // drop "usage:"
pu := strings.Fields(section)
if len(pu) == 0 {
return "", newLanguageError("no fields found in usage (perhaps a spacing error).")
}
result := "( "
for _, s := range pu[1:] {
if s == pu[0] {
result += ") | ( "
} else {
result += s + " "
}
}
result += ")"
return result, nil
}
func extras(help bool, version string, options patternList, doc string) string {
if help {
for _, o := range options {
if (o.name == "-h" || o.name == "--help") && o.value == true {
return strings.Trim(doc, "\n")
}
}
}
if version != "" {
for _, o := range options {
if (o.name == "--version") && o.value == true {
return version
}
}
}
return ""
}
func stringPartition(s, sep string) (string, string, string) {
sepPos := strings.Index(s, sep)
if sepPos == -1 { // no seperator found
return s, "", ""
}
split := strings.SplitN(s, sep, 2)
return split[0], sep, split[1]
}

49
vendor/github.com/docopt/docopt-go/error.go generated vendored Normal file
View file

@ -0,0 +1,49 @@
package docopt
import (
"fmt"
)
type errorType int
const (
errorUser errorType = iota
errorLanguage
)
func (e errorType) String() string {
switch e {
case errorUser:
return "errorUser"
case errorLanguage:
return "errorLanguage"
}
return ""
}
// UserError records an error with program arguments.
type UserError struct {
msg string
Usage string
}
func (e UserError) Error() string {
return e.msg
}
func newUserError(msg string, f ...interface{}) error {
return &UserError{fmt.Sprintf(msg, f...), ""}
}
// LanguageError records an error with the doc string.
type LanguageError struct {
msg string
}
func (e LanguageError) Error() string {
return e.msg
}
func newLanguageError(msg string, f ...interface{}) error {
return &LanguageError{fmt.Sprintf(msg, f...)}
}
var newError = fmt.Errorf

264
vendor/github.com/docopt/docopt-go/opts.go generated vendored Normal file
View file

@ -0,0 +1,264 @@
package docopt
import (
"fmt"
"reflect"
"strconv"
"strings"
"unicode"
)
func errKey(key string) error {
return fmt.Errorf("no such key: %q", key)
}
func errType(key string) error {
return fmt.Errorf("key: %q failed type conversion", key)
}
func errStrconv(key string, convErr error) error {
return fmt.Errorf("key: %q failed type conversion: %s", key, convErr)
}
// Opts is a map of command line options to their values, with some convenience
// methods for value type conversion (bool, float64, int, string). For example,
// to get an option value as an int:
//
// opts, _ := docopt.ParseDoc("Usage: sleep <seconds>")
// secs, _ := opts.Int("<seconds>")
//
// Additionally, Opts.Bind allows you easily populate a struct's fields with the
// values of each option value. See below for examples.
//
// Lastly, you can still treat Opts as a regular map, and do any type checking
// and conversion that you want to yourself. For example:
//
// if s, ok := opts["<binary>"].(string); ok {
// if val, err := strconv.ParseUint(s, 2, 64); err != nil { ... }
// }
//
// Note that any non-boolean option / flag will have a string value in the
// underlying map.
type Opts map[string]interface{}
func (o Opts) String(key string) (s string, err error) {
v, ok := o[key]
if !ok {
err = errKey(key)
return
}
s, ok = v.(string)
if !ok {
err = errType(key)
}
return
}
func (o Opts) Bool(key string) (b bool, err error) {
v, ok := o[key]
if !ok {
err = errKey(key)
return
}
b, ok = v.(bool)
if !ok {
err = errType(key)
}
return
}
func (o Opts) Int(key string) (i int, err error) {
s, err := o.String(key)
if err != nil {
return
}
i, err = strconv.Atoi(s)
if err != nil {
err = errStrconv(key, err)
}
return
}
func (o Opts) Float64(key string) (f float64, err error) {
s, err := o.String(key)
if err != nil {
return
}
f, err = strconv.ParseFloat(s, 64)
if err != nil {
err = errStrconv(key, err)
}
return
}
// Bind populates the fields of a given struct with matching option values.
// Each key in Opts will be mapped to an exported field of the struct pointed
// to by `v`, as follows:
//
// abc int // Unexported field, ignored
// Abc string // Mapped from `--abc`, `<abc>`, or `abc`
// // (case insensitive)
// A string // Mapped from `-a`, `<a>` or `a`
// // (case insensitive)
// Abc int `docopt:"XYZ"` // Mapped from `XYZ`
// Abc bool `docopt:"-"` // Mapped from `-`
// Abc bool `docopt:"-x,--xyz"` // Mapped from `-x` or `--xyz`
// // (first non-zero value found)
//
// Tagged (annotated) fields will always be mapped first. If no field is tagged
// with an option's key, Bind will try to map the option to an appropriately
// named field (as above).
//
// Bind also handles conversion to bool, float, int or string types.
func (o Opts) Bind(v interface{}) error {
structVal := reflect.ValueOf(v)
if structVal.Kind() != reflect.Ptr {
return newError("'v' argument is not pointer to struct type")
}
for structVal.Kind() == reflect.Ptr {
structVal = structVal.Elem()
}
if structVal.Kind() != reflect.Struct {
return newError("'v' argument is not pointer to struct type")
}
structType := structVal.Type()
tagged := make(map[string]int) // Tagged field tags
untagged := make(map[string]int) // Untagged field names
for i := 0; i < structType.NumField(); i++ {
field := structType.Field(i)
if isUnexportedField(field) || field.Anonymous {
continue
}
tag := field.Tag.Get("docopt")
if tag == "" {
untagged[field.Name] = i
continue
}
for _, t := range strings.Split(tag, ",") {
tagged[t] = i
}
}
// Get the index of the struct field to use, based on the option key.
// Second argument is true/false on whether something was matched.
getFieldIndex := func(key string) (int, bool) {
if i, ok := tagged[key]; ok {
return i, true
}
if i, ok := untagged[guessUntaggedField(key)]; ok {
return i, true
}
return -1, false
}
indexMap := make(map[string]int) // Option keys to field index
// Pre-check that option keys are mapped to fields and fields are zero valued, before populating them.
for k := range o {
i, ok := getFieldIndex(k)
if !ok {
if k == "--help" || k == "--version" { // Don't require these to be mapped.
continue
}
return newError("mapping of %q is not found in given struct, or is an unexported field", k)
}
fieldVal := structVal.Field(i)
zeroVal := reflect.Zero(fieldVal.Type())
if !reflect.DeepEqual(fieldVal.Interface(), zeroVal.Interface()) {
return newError("%q field is non-zero, will be overwritten by value of %q", structType.Field(i).Name, k)
}
indexMap[k] = i
}
// Populate fields with option values.
for k, v := range o {
i, ok := indexMap[k]
if !ok {
continue // Not mapped.
}
field := structVal.Field(i)
if !reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()) {
// The struct's field is already non-zero (by our doing), so don't change it.
// This happens with comma separated tags, e.g. `docopt:"-h,--help"` which is a
// convenient way of checking if one of multiple boolean flags are set.
continue
}
optVal := reflect.ValueOf(v)
// Option value is the zero Value, so we can't get its .Type(). No need to assign anyway, so move along.
if !optVal.IsValid() {
continue
}
if !field.CanSet() {
return newError("%q field cannot be set", structType.Field(i).Name)
}
// Try to assign now if able. bool and string values should be assignable already.
if optVal.Type().AssignableTo(field.Type()) {
field.Set(optVal)
continue
}
// Try to convert the value and assign if able.
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if x, err := o.Int(k); err == nil {
field.SetInt(int64(x))
continue
}
case reflect.Float32, reflect.Float64:
if x, err := o.Float64(k); err == nil {
field.SetFloat(x)
continue
}
}
// TODO: Something clever (recursive?) with non-string slices.
// case reflect.Slice:
// if optVal.Kind() == reflect.Slice {
// for i := 0; i < optVal.Len(); i++ {
// sliceVal := optVal.Index(i)
// fmt.Printf("%v", sliceVal)
// }
// fmt.Printf("\n")
// }
return newError("value of %q is not assignable to %q field", k, structType.Field(i).Name)
}
return nil
}
// isUnexportedField returns whether the field is unexported.
// isUnexportedField is to avoid the bug in versions older than Go1.3.
// See following links:
// https://code.google.com/p/go/issues/detail?id=7247
// http://golang.org/ref/spec#Exported_identifiers
func isUnexportedField(field reflect.StructField) bool {
return !(field.PkgPath == "" && unicode.IsUpper(rune(field.Name[0])))
}
// Convert a string like "--my-special-flag" to "MySpecialFlag".
func titleCaseDashes(key string) string {
nextToUpper := true
mapFn := func(r rune) rune {
if r == '-' {
nextToUpper = true
return -1
}
if nextToUpper {
nextToUpper = false
return unicode.ToUpper(r)
}
return r
}
return strings.Map(mapFn, key)
}
// Best guess which field.Name in a struct to assign for an option key.
func guessUntaggedField(key string) string {
switch {
case strings.HasPrefix(key, "--") && len(key[2:]) > 1:
return titleCaseDashes(key[2:])
case strings.HasPrefix(key, "-") && len(key[1:]) == 1:
return titleCaseDashes(key[1:])
case strings.HasPrefix(key, "<") && strings.HasSuffix(key, ">"):
key = key[1 : len(key)-1]
}
return strings.Title(strings.ToLower(key))
}

550
vendor/github.com/docopt/docopt-go/pattern.go generated vendored Normal file
View file

@ -0,0 +1,550 @@
package docopt
import (
"fmt"
"reflect"
"strings"
)
type patternType uint
const (
// leaf
patternArgument patternType = 1 << iota
patternCommand
patternOption
// branch
patternRequired
patternOptionAL
patternOptionSSHORTCUT // Marker/placeholder for [options] shortcut.
patternOneOrMore
patternEither
patternLeaf = patternArgument +
patternCommand +
patternOption
patternBranch = patternRequired +
patternOptionAL +
patternOptionSSHORTCUT +
patternOneOrMore +
patternEither
patternAll = patternLeaf + patternBranch
patternDefault = 0
)
func (pt patternType) String() string {
switch pt {
case patternArgument:
return "argument"
case patternCommand:
return "command"
case patternOption:
return "option"
case patternRequired:
return "required"
case patternOptionAL:
return "optional"
case patternOptionSSHORTCUT:
return "optionsshortcut"
case patternOneOrMore:
return "oneormore"
case patternEither:
return "either"
case patternLeaf:
return "leaf"
case patternBranch:
return "branch"
case patternAll:
return "all"
case patternDefault:
return "default"
}
return ""
}
type pattern struct {
t patternType
children patternList
name string
value interface{}
short string
long string
argcount int
}
type patternList []*pattern
func newBranchPattern(t patternType, pl ...*pattern) *pattern {
var p pattern
p.t = t
p.children = make(patternList, len(pl))
copy(p.children, pl)
return &p
}
func newRequired(pl ...*pattern) *pattern {
return newBranchPattern(patternRequired, pl...)
}
func newEither(pl ...*pattern) *pattern {
return newBranchPattern(patternEither, pl...)
}
func newOneOrMore(pl ...*pattern) *pattern {
return newBranchPattern(patternOneOrMore, pl...)
}
func newOptional(pl ...*pattern) *pattern {
return newBranchPattern(patternOptionAL, pl...)
}
func newOptionsShortcut() *pattern {
var p pattern
p.t = patternOptionSSHORTCUT
return &p
}
func newLeafPattern(t patternType, name string, value interface{}) *pattern {
// default: value=nil
var p pattern
p.t = t
p.name = name
p.value = value
return &p
}
func newArgument(name string, value interface{}) *pattern {
// default: value=nil
return newLeafPattern(patternArgument, name, value)
}
func newCommand(name string, value interface{}) *pattern {
// default: value=false
var p pattern
p.t = patternCommand
p.name = name
p.value = value
return &p
}
func newOption(short, long string, argcount int, value interface{}) *pattern {
// default: "", "", 0, false
var p pattern
p.t = patternOption
p.short = short
p.long = long
if long != "" {
p.name = long
} else {
p.name = short
}
p.argcount = argcount
if value == false && argcount > 0 {
p.value = nil
} else {
p.value = value
}
return &p
}
func (p *pattern) flat(types patternType) (patternList, error) {
if p.t&patternLeaf != 0 {
if types == patternDefault {
types = patternAll
}
if p.t&types != 0 {
return patternList{p}, nil
}
return patternList{}, nil
}
if p.t&patternBranch != 0 {
if p.t&types != 0 {
return patternList{p}, nil
}
result := patternList{}
for _, child := range p.children {
childFlat, err := child.flat(types)
if err != nil {
return nil, err
}
result = append(result, childFlat...)
}
return result, nil
}
return nil, newError("unknown pattern type: %d, %d", p.t, types)
}
func (p *pattern) fix() error {
err := p.fixIdentities(nil)
if err != nil {
return err
}
p.fixRepeatingArguments()
return nil
}
func (p *pattern) fixIdentities(uniq patternList) error {
// Make pattern-tree tips point to same object if they are equal.
if p.t&patternBranch == 0 {
return nil
}
if uniq == nil {
pFlat, err := p.flat(patternDefault)
if err != nil {
return err
}
uniq = pFlat.unique()
}
for i, child := range p.children {
if child.t&patternBranch == 0 {
ind, err := uniq.index(child)
if err != nil {
return err
}
p.children[i] = uniq[ind]
} else {
err := child.fixIdentities(uniq)
if err != nil {
return err
}
}
}
return nil
}
func (p *pattern) fixRepeatingArguments() {
// Fix elements that should accumulate/increment values.
var either []patternList
for _, child := range p.transform().children {
either = append(either, child.children)
}
for _, cas := range either {
casMultiple := patternList{}
for _, e := range cas {
if cas.count(e) > 1 {
casMultiple = append(casMultiple, e)
}
}
for _, e := range casMultiple {
if e.t == patternArgument || e.t == patternOption && e.argcount > 0 {
switch e.value.(type) {
case string:
e.value = strings.Fields(e.value.(string))
case []string:
default:
e.value = []string{}
}
}
if e.t == patternCommand || e.t == patternOption && e.argcount == 0 {
e.value = 0
}
}
}
}
func (p *pattern) match(left *patternList, collected *patternList) (bool, *patternList, *patternList) {
if collected == nil {
collected = &patternList{}
}
if p.t&patternRequired != 0 {
l := left
c := collected
for _, p := range p.children {
var matched bool
matched, l, c = p.match(l, c)
if !matched {
return false, left, collected
}
}
return true, l, c
} else if p.t&patternOptionAL != 0 || p.t&patternOptionSSHORTCUT != 0 {
for _, p := range p.children {
_, left, collected = p.match(left, collected)
}
return true, left, collected
} else if p.t&patternOneOrMore != 0 {
if len(p.children) != 1 {
panic("OneOrMore.match(): assert len(p.children) == 1")
}
l := left
c := collected
var lAlt *patternList
matched := true
times := 0
for matched {
// could it be that something didn't match but changed l or c?
matched, l, c = p.children[0].match(l, c)
if matched {
times++
}
if lAlt == l {
break
}
lAlt = l
}
if times >= 1 {
return true, l, c
}
return false, left, collected
} else if p.t&patternEither != 0 {
type outcomeStruct struct {
matched bool
left *patternList
collected *patternList
length int
}
outcomes := []outcomeStruct{}
for _, p := range p.children {
matched, l, c := p.match(left, collected)
outcome := outcomeStruct{matched, l, c, len(*l)}
if matched {
outcomes = append(outcomes, outcome)
}
}
if len(outcomes) > 0 {
minLen := outcomes[0].length
minIndex := 0
for i, v := range outcomes {
if v.length < minLen {
minIndex = i
}
}
return outcomes[minIndex].matched, outcomes[minIndex].left, outcomes[minIndex].collected
}
return false, left, collected
} else if p.t&patternLeaf != 0 {
pos, match := p.singleMatch(left)
var increment interface{}
if match == nil {
return false, left, collected
}
leftAlt := make(patternList, len((*left)[:pos]), len((*left)[:pos])+len((*left)[pos+1:]))
copy(leftAlt, (*left)[:pos])
leftAlt = append(leftAlt, (*left)[pos+1:]...)
sameName := patternList{}
for _, a := range *collected {
if a.name == p.name {
sameName = append(sameName, a)
}
}
switch p.value.(type) {
case int, []string:
switch p.value.(type) {
case int:
increment = 1
case []string:
switch match.value.(type) {
case string:
increment = []string{match.value.(string)}
default:
increment = match.value
}
}
if len(sameName) == 0 {
match.value = increment
collectedMatch := make(patternList, len(*collected), len(*collected)+1)
copy(collectedMatch, *collected)
collectedMatch = append(collectedMatch, match)
return true, &leftAlt, &collectedMatch
}
switch sameName[0].value.(type) {
case int:
sameName[0].value = sameName[0].value.(int) + increment.(int)
case []string:
sameName[0].value = append(sameName[0].value.([]string), increment.([]string)...)
}
return true, &leftAlt, collected
}
collectedMatch := make(patternList, len(*collected), len(*collected)+1)
copy(collectedMatch, *collected)
collectedMatch = append(collectedMatch, match)
return true, &leftAlt, &collectedMatch
}
panic("unmatched type")
}
func (p *pattern) singleMatch(left *patternList) (int, *pattern) {
if p.t&patternArgument != 0 {
for n, pat := range *left {
if pat.t&patternArgument != 0 {
return n, newArgument(p.name, pat.value)
}
}
return -1, nil
} else if p.t&patternCommand != 0 {
for n, pat := range *left {
if pat.t&patternArgument != 0 {
if pat.value == p.name {
return n, newCommand(p.name, true)
}
break
}
}
return -1, nil
} else if p.t&patternOption != 0 {
for n, pat := range *left {
if p.name == pat.name {
return n, pat
}
}
return -1, nil
}
panic("unmatched type")
}
func (p *pattern) String() string {
if p.t&patternOption != 0 {
return fmt.Sprintf("%s(%s, %s, %d, %+v)", p.t, p.short, p.long, p.argcount, p.value)
} else if p.t&patternLeaf != 0 {
return fmt.Sprintf("%s(%s, %+v)", p.t, p.name, p.value)
} else if p.t&patternBranch != 0 {
result := ""
for i, child := range p.children {
if i > 0 {
result += ", "
}
result += child.String()
}
return fmt.Sprintf("%s(%s)", p.t, result)
}
panic("unmatched type")
}
func (p *pattern) transform() *pattern {
/*
Expand pattern into an (almost) equivalent one, but with single Either.
Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
Quirks: [-a] => (-a), (-a...) => (-a -a)
*/
result := []patternList{}
groups := []patternList{patternList{p}}
parents := patternRequired +
patternOptionAL +
patternOptionSSHORTCUT +
patternEither +
patternOneOrMore
for len(groups) > 0 {
children := groups[0]
groups = groups[1:]
var child *pattern
for _, c := range children {
if c.t&parents != 0 {
child = c
break
}
}
if child != nil {
children.remove(child)
if child.t&patternEither != 0 {
for _, c := range child.children {
r := patternList{}
r = append(r, c)
r = append(r, children...)
groups = append(groups, r)
}
} else if child.t&patternOneOrMore != 0 {
r := patternList{}
r = append(r, child.children.double()...)
r = append(r, children...)
groups = append(groups, r)
} else {
r := patternList{}
r = append(r, child.children...)
r = append(r, children...)
groups = append(groups, r)
}
} else {
result = append(result, children)
}
}
either := patternList{}
for _, e := range result {
either = append(either, newRequired(e...))
}
return newEither(either...)
}
func (p *pattern) eq(other *pattern) bool {
return reflect.DeepEqual(p, other)
}
func (pl patternList) unique() patternList {
table := make(map[string]bool)
result := patternList{}
for _, v := range pl {
if !table[v.String()] {
table[v.String()] = true
result = append(result, v)
}
}
return result
}
func (pl patternList) index(p *pattern) (int, error) {
for i, c := range pl {
if c.eq(p) {
return i, nil
}
}
return -1, newError("%s not in list", p)
}
func (pl patternList) count(p *pattern) int {
count := 0
for _, c := range pl {
if c.eq(p) {
count++
}
}
return count
}
func (pl patternList) diff(l patternList) patternList {
lAlt := make(patternList, len(l))
copy(lAlt, l)
result := make(patternList, 0, len(pl))
for _, v := range pl {
if v != nil {
match := false
for i, w := range lAlt {
if w.eq(v) {
match = true
lAlt[i] = nil
break
}
}
if match == false {
result = append(result, v)
}
}
}
return result
}
func (pl patternList) double() patternList {
l := len(pl)
result := make(patternList, l*2)
copy(result, pl)
copy(result[l:2*l], pl)
return result
}
func (pl *patternList) remove(p *pattern) {
(*pl) = pl.diff(patternList{p})
}
func (pl patternList) dictionary() map[string]interface{} {
dict := make(map[string]interface{})
for _, a := range pl {
dict[a.name] = a.value
}
return dict
}

View file

@ -0,0 +1,9 @@
r"""usage: prog [NAME_-2]..."""
$ prog 10 20
{"NAME_-2": ["10", "20"]}
$ prog 10
{"NAME_-2": ["10"]}
$ prog
{"NAME_-2": []}

957
vendor/github.com/docopt/docopt-go/testcases.docopt generated vendored Normal file
View file

@ -0,0 +1,957 @@
r"""Usage: prog
"""
$ prog
{}
$ prog --xxx
"user-error"
r"""Usage: prog [options]
Options: -a All.
"""
$ prog
{"-a": false}
$ prog -a
{"-a": true}
$ prog -x
"user-error"
r"""Usage: prog [options]
Options: --all All.
"""
$ prog
{"--all": false}
$ prog --all
{"--all": true}
$ prog --xxx
"user-error"
r"""Usage: prog [options]
Options: -v, --verbose Verbose.
"""
$ prog --verbose
{"--verbose": true}
$ prog --ver
{"--verbose": true}
$ prog -v
{"--verbose": true}
r"""Usage: prog [options]
Options: -p PATH
"""
$ prog -p home/
{"-p": "home/"}
$ prog -phome/
{"-p": "home/"}
$ prog -p
"user-error"
r"""Usage: prog [options]
Options: --path <path>
"""
$ prog --path home/
{"--path": "home/"}
$ prog --path=home/
{"--path": "home/"}
$ prog --pa home/
{"--path": "home/"}
$ prog --pa=home/
{"--path": "home/"}
$ prog --path
"user-error"
r"""Usage: prog [options]
Options: -p PATH, --path=<path> Path to files.
"""
$ prog -proot
{"--path": "root"}
r"""Usage: prog [options]
Options: -p --path PATH Path to files.
"""
$ prog -p root
{"--path": "root"}
$ prog --path root
{"--path": "root"}
r"""Usage: prog [options]
Options:
-p PATH Path to files [default: ./]
"""
$ prog
{"-p": "./"}
$ prog -phome
{"-p": "home"}
r"""UsAgE: prog [options]
OpTiOnS: --path=<files> Path to files
[dEfAuLt: /root]
"""
$ prog
{"--path": "/root"}
$ prog --path=home
{"--path": "home"}
r"""usage: prog [options]
options:
-a Add
-r Remote
-m <msg> Message
"""
$ prog -a -r -m Hello
{"-a": true,
"-r": true,
"-m": "Hello"}
$ prog -armyourass
{"-a": true,
"-r": true,
"-m": "yourass"}
$ prog -a -r
{"-a": true,
"-r": true,
"-m": null}
r"""Usage: prog [options]
Options: --version
--verbose
"""
$ prog --version
{"--version": true,
"--verbose": false}
$ prog --verbose
{"--version": false,
"--verbose": true}
$ prog --ver
"user-error"
$ prog --verb
{"--version": false,
"--verbose": true}
r"""usage: prog [-a -r -m <msg>]
options:
-a Add
-r Remote
-m <msg> Message
"""
$ prog -armyourass
{"-a": true,
"-r": true,
"-m": "yourass"}
r"""usage: prog [-armmsg]
options: -a Add
-r Remote
-m <msg> Message
"""
$ prog -a -r -m Hello
{"-a": true,
"-r": true,
"-m": "Hello"}
r"""usage: prog -a -b
options:
-a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog
"user-error"
r"""usage: prog (-a -b)
options: -a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog
"user-error"
r"""usage: prog [-a] -b
options: -a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog -b
{"-a": false, "-b": true}
$ prog
"user-error"
r"""usage: prog [(-a -b)]
options: -a
-b
"""
$ prog -a -b
{"-a": true, "-b": true}
$ prog -b -a
{"-a": true, "-b": true}
$ prog -a
"user-error"
$ prog -b
"user-error"
$ prog
{"-a": false, "-b": false}
r"""usage: prog (-a|-b)
options: -a
-b
"""
$ prog -a -b
"user-error"
$ prog
"user-error"
$ prog -a
{"-a": true, "-b": false}
$ prog -b
{"-a": false, "-b": true}
r"""usage: prog [ -a | -b ]
options: -a
-b
"""
$ prog -a -b
"user-error"
$ prog
{"-a": false, "-b": false}
$ prog -a
{"-a": true, "-b": false}
$ prog -b
{"-a": false, "-b": true}
r"""usage: prog <arg>"""
$ prog 10
{"<arg>": "10"}
$ prog 10 20
"user-error"
$ prog
"user-error"
r"""usage: prog [<arg>]"""
$ prog 10
{"<arg>": "10"}
$ prog 10 20
"user-error"
$ prog
{"<arg>": null}
r"""usage: prog <kind> <name> <type>"""
$ prog 10 20 40
{"<kind>": "10", "<name>": "20", "<type>": "40"}
$ prog 10 20
"user-error"
$ prog
"user-error"
r"""usage: prog <kind> [<name> <type>]"""
$ prog 10 20 40
{"<kind>": "10", "<name>": "20", "<type>": "40"}
$ prog 10 20
{"<kind>": "10", "<name>": "20", "<type>": null}
$ prog
"user-error"
r"""usage: prog [<kind> | <name> <type>]"""
$ prog 10 20 40
"user-error"
$ prog 20 40
{"<kind>": null, "<name>": "20", "<type>": "40"}
$ prog
{"<kind>": null, "<name>": null, "<type>": null}
r"""usage: prog (<kind> --all | <name>)
options:
--all
"""
$ prog 10 --all
{"<kind>": "10", "--all": true, "<name>": null}
$ prog 10
{"<kind>": null, "--all": false, "<name>": "10"}
$ prog
"user-error"
r"""usage: prog [<name> <name>]"""
$ prog 10 20
{"<name>": ["10", "20"]}
$ prog 10
{"<name>": ["10"]}
$ prog
{"<name>": []}
r"""usage: prog [(<name> <name>)]"""
$ prog 10 20
{"<name>": ["10", "20"]}
$ prog 10
"user-error"
$ prog
{"<name>": []}
r"""usage: prog NAME..."""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
"user-error"
r"""usage: prog [NAME]..."""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
{"NAME": []}
r"""usage: prog [NAME...]"""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
{"NAME": []}
r"""usage: prog [NAME [NAME ...]]"""
$ prog 10 20
{"NAME": ["10", "20"]}
$ prog 10
{"NAME": ["10"]}
$ prog
{"NAME": []}
r"""usage: prog (NAME | --foo NAME)
options: --foo
"""
$ prog 10
{"NAME": "10", "--foo": false}
$ prog --foo 10
{"NAME": "10", "--foo": true}
$ prog --foo=10
"user-error"
r"""usage: prog (NAME | --foo) [--bar | NAME]
options: --foo
options: --bar
"""
$ prog 10
{"NAME": ["10"], "--foo": false, "--bar": false}
$ prog 10 20
{"NAME": ["10", "20"], "--foo": false, "--bar": false}
$ prog --foo --bar
{"NAME": [], "--foo": true, "--bar": true}
r"""Naval Fate.
Usage:
prog ship new <name>...
prog ship [<name>] move <x> <y> [--speed=<kn>]
prog ship shoot <x> <y>
prog mine (set|remove) <x> <y> [--moored|--drifting]
prog -h | --help
prog --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Mored (anchored) mine.
--drifting Drifting mine.
"""
$ prog ship Guardian move 150 300 --speed=20
{"--drifting": false,
"--help": false,
"--moored": false,
"--speed": "20",
"--version": false,
"<name>": ["Guardian"],
"<x>": "150",
"<y>": "300",
"mine": false,
"move": true,
"new": false,
"remove": false,
"set": false,
"ship": true,
"shoot": false}
r"""usage: prog --hello"""
$ prog --hello
{"--hello": true}
r"""usage: prog [--hello=<world>]"""
$ prog
{"--hello": null}
$ prog --hello wrld
{"--hello": "wrld"}
r"""usage: prog [-o]"""
$ prog
{"-o": false}
$ prog -o
{"-o": true}
r"""usage: prog [-opr]"""
$ prog -op
{"-o": true, "-p": true, "-r": false}
r"""usage: prog --aabb | --aa"""
$ prog --aa
{"--aabb": false, "--aa": true}
$ prog --a
"user-error" # not a unique prefix
#
# Counting number of flags
#
r"""Usage: prog -v"""
$ prog -v
{"-v": true}
r"""Usage: prog [-v -v]"""
$ prog
{"-v": 0}
$ prog -v
{"-v": 1}
$ prog -vv
{"-v": 2}
r"""Usage: prog -v ..."""
$ prog
"user-error"
$ prog -v
{"-v": 1}
$ prog -vv
{"-v": 2}
$ prog -vvvvvv
{"-v": 6}
r"""Usage: prog [-v | -vv | -vvv]
This one is probably most readable user-friednly variant.
"""
$ prog
{"-v": 0}
$ prog -v
{"-v": 1}
$ prog -vv
{"-v": 2}
$ prog -vvvv
"user-error"
r"""usage: prog [--ver --ver]"""
$ prog --ver --ver
{"--ver": 2}
#
# Counting commands
#
r"""usage: prog [go]"""
$ prog go
{"go": true}
r"""usage: prog [go go]"""
$ prog
{"go": 0}
$ prog go
{"go": 1}
$ prog go go
{"go": 2}
$ prog go go go
"user-error"
r"""usage: prog go..."""
$ prog go go go go go
{"go": 5}
#
# [options] does not include options from usage-pattern
#
r"""usage: prog [options] [-a]
options: -a
-b
"""
$ prog -a
{"-a": true, "-b": false}
$ prog -aa
"user-error"
#
# Test [options] shourtcut
#
r"""Usage: prog [options] A
Options:
-q Be quiet
-v Be verbose.
"""
$ prog arg
{"A": "arg", "-v": false, "-q": false}
$ prog -v arg
{"A": "arg", "-v": true, "-q": false}
$ prog -q arg
{"A": "arg", "-v": false, "-q": true}
#
# Test single dash
#
r"""usage: prog [-]"""
$ prog -
{"-": true}
$ prog
{"-": false}
#
# If argument is repeated, its value should always be a list
#
r"""usage: prog [NAME [NAME ...]]"""
$ prog a b
{"NAME": ["a", "b"]}
$ prog
{"NAME": []}
#
# Option's argument defaults to null/None
#
r"""usage: prog [options]
options:
-a Add
-m <msg> Message
"""
$ prog -a
{"-m": null, "-a": true}
#
# Test options without description
#
r"""usage: prog --hello"""
$ prog --hello
{"--hello": true}
r"""usage: prog [--hello=<world>]"""
$ prog
{"--hello": null}
$ prog --hello wrld
{"--hello": "wrld"}
r"""usage: prog [-o]"""
$ prog
{"-o": false}
$ prog -o
{"-o": true}
r"""usage: prog [-opr]"""
$ prog -op
{"-o": true, "-p": true, "-r": false}
r"""usage: git [-v | --verbose]"""
$ prog -v
{"-v": true, "--verbose": false}
r"""usage: git remote [-v | --verbose]"""
$ prog remote -v
{"remote": true, "-v": true, "--verbose": false}
#
# Test empty usage pattern
#
r"""usage: prog"""
$ prog
{}
r"""usage: prog
prog <a> <b>
"""
$ prog 1 2
{"<a>": "1", "<b>": "2"}
$ prog
{"<a>": null, "<b>": null}
r"""usage: prog <a> <b>
prog
"""
$ prog
{"<a>": null, "<b>": null}
#
# Option's argument should not capture default value from usage pattern
#
r"""usage: prog [--file=<f>]"""
$ prog
{"--file": null}
r"""usage: prog [--file=<f>]
options: --file <a>
"""
$ prog
{"--file": null}
r"""Usage: prog [-a <host:port>]
Options: -a, --address <host:port> TCP address [default: localhost:6283].
"""
$ prog
{"--address": "localhost:6283"}
#
# If option with argument could be repeated,
# its arguments should be accumulated into a list
#
r"""usage: prog --long=<arg> ..."""
$ prog --long one
{"--long": ["one"]}
$ prog --long one --long two
{"--long": ["one", "two"]}
#
# Test multiple elements repeated at once
#
r"""usage: prog (go <direction> --speed=<km/h>)..."""
$ prog go left --speed=5 go right --speed=9
{"go": 2, "<direction>": ["left", "right"], "--speed": ["5", "9"]}
#
# Required options should work with option shortcut
#
r"""usage: prog [options] -a
options: -a
"""
$ prog -a
{"-a": true}
#
# If option could be repeated its defaults should be split into a list
#
r"""usage: prog [-o <o>]...
options: -o <o> [default: x]
"""
$ prog -o this -o that
{"-o": ["this", "that"]}
$ prog
{"-o": ["x"]}
r"""usage: prog [-o <o>]...
options: -o <o> [default: x y]
"""
$ prog -o this
{"-o": ["this"]}
$ prog
{"-o": ["x", "y"]}
#
# Test stacked option's argument
#
r"""usage: prog -pPATH
options: -p PATH
"""
$ prog -pHOME
{"-p": "HOME"}
#
# Issue 56: Repeated mutually exclusive args give nested lists sometimes
#
r"""Usage: foo (--xx=x|--yy=y)..."""
$ prog --xx=1 --yy=2
{"--xx": ["1"], "--yy": ["2"]}
#
# POSIXly correct tokenization
#
r"""usage: prog [<input file>]"""
$ prog f.txt
{"<input file>": "f.txt"}
r"""usage: prog [--input=<file name>]..."""
$ prog --input a.txt --input=b.txt
{"--input": ["a.txt", "b.txt"]}
#
# Issue 85: `[options]` shourtcut with multiple subcommands
#
r"""usage: prog good [options]
prog fail [options]
options: --loglevel=N
"""
$ prog fail --loglevel 5
{"--loglevel": "5", "fail": true, "good": false}
#
# Usage-section syntax
#
r"""usage:prog --foo"""
$ prog --foo
{"--foo": true}
r"""PROGRAM USAGE: prog --foo"""
$ prog --foo
{"--foo": true}
r"""Usage: prog --foo
prog --bar
NOT PART OF SECTION"""
$ prog --foo
{"--foo": true, "--bar": false}
r"""Usage:
prog --foo
prog --bar
NOT PART OF SECTION"""
$ prog --foo
{"--foo": true, "--bar": false}
r"""Usage:
prog --foo
prog --bar
NOT PART OF SECTION"""
$ prog --foo
{"--foo": true, "--bar": false}
#
# Options-section syntax
#
r"""Usage: prog [options]
global options: --foo
local options: --baz
--bar
other options:
--egg
--spam
-not-an-option-
"""
$ prog --baz --egg
{"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}

126
vendor/github.com/docopt/docopt-go/token.go generated vendored Normal file
View file

@ -0,0 +1,126 @@
package docopt
import (
"regexp"
"strings"
"unicode"
)
type tokenList struct {
tokens []string
errorFunc func(string, ...interface{}) error
err errorType
}
type token string
func newTokenList(source []string, err errorType) *tokenList {
errorFunc := newError
if err == errorUser {
errorFunc = newUserError
} else if err == errorLanguage {
errorFunc = newLanguageError
}
return &tokenList{source, errorFunc, err}
}
func tokenListFromString(source string) *tokenList {
return newTokenList(strings.Fields(source), errorUser)
}
func tokenListFromPattern(source string) *tokenList {
p := regexp.MustCompile(`([\[\]\(\)\|]|\.\.\.)`)
source = p.ReplaceAllString(source, ` $1 `)
p = regexp.MustCompile(`\s+|(\S*<.*?>)`)
split := p.Split(source, -1)
match := p.FindAllStringSubmatch(source, -1)
var result []string
l := len(split)
for i := 0; i < l; i++ {
if len(split[i]) > 0 {
result = append(result, split[i])
}
if i < l-1 && len(match[i][1]) > 0 {
result = append(result, match[i][1])
}
}
return newTokenList(result, errorLanguage)
}
func (t *token) eq(s string) bool {
if t == nil {
return false
}
return string(*t) == s
}
func (t *token) match(matchNil bool, tokenStrings ...string) bool {
if t == nil && matchNil {
return true
} else if t == nil && !matchNil {
return false
}
for _, tok := range tokenStrings {
if tok == string(*t) {
return true
}
}
return false
}
func (t *token) hasPrefix(prefix string) bool {
if t == nil {
return false
}
return strings.HasPrefix(string(*t), prefix)
}
func (t *token) hasSuffix(suffix string) bool {
if t == nil {
return false
}
return strings.HasSuffix(string(*t), suffix)
}
func (t *token) isUpper() bool {
if t == nil {
return false
}
return isStringUppercase(string(*t))
}
func (t *token) String() string {
if t == nil {
return ""
}
return string(*t)
}
func (tl *tokenList) current() *token {
if len(tl.tokens) > 0 {
return (*token)(&(tl.tokens[0]))
}
return nil
}
func (tl *tokenList) length() int {
return len(tl.tokens)
}
func (tl *tokenList) move() *token {
if len(tl.tokens) > 0 {
t := tl.tokens[0]
tl.tokens = tl.tokens[1:]
return (*token)(&t)
}
return nil
}
// returns true if all cased characters in the string are uppercase
// and there are there is at least one cased charcter
func isStringUppercase(s string) bool {
if strings.ToUpper(s) != s {
return false
}
for _, c := range []rune(s) {
if unicode.IsUpper(c) {
return true
}
}
return false
}