mirror of
https://github.com/cjbassi/gotop.git
synced 2025-04-27 13:48:54 +08:00
Fixed docopt dep version issue
This commit is contained in:
parent
da98e5421b
commit
3cc1e4ebfc
6
Gopkg.lock
generated
6
Gopkg.lock
generated
@ -20,10 +20,10 @@
|
|||||||
revision = "d8e7d6f2c53c6f045c1d95c9fa9968e4d2ba569e"
|
revision = "d8e7d6f2c53c6f045c1d95c9fa9968e4d2ba569e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/docopt/docopt-go"
|
name = "github.com/docopt/docopt-go"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "784ddc588536785e7299f7272f39101f7faccc3f"
|
revision = "ee0de3bc6815ee19d4a46c7eb90f829db0e014b1"
|
||||||
version = "0.6.2"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/go-ole/go-ole"
|
name = "github.com/go-ole/go-ole"
|
||||||
@ -78,6 +78,6 @@
|
|||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "d2076f778d670ace1a8d4ddb709c3421637ec24b72e6e8502e5bbf41e93def62"
|
inputs-digest = "22a656ce826eed217bf58555e692a26e2d791e256a6f17b8b06b9c964bb30f11"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
29
Gopkg.toml
29
Gopkg.toml
@ -1,37 +1,10 @@
|
|||||||
# Gopkg.toml example
|
|
||||||
#
|
|
||||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
|
||||||
# for detailed Gopkg.toml documentation.
|
|
||||||
#
|
|
||||||
# required = ["github.com/user/thing/cmd/thing"]
|
|
||||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project"
|
|
||||||
# version = "1.0.0"
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project2"
|
|
||||||
# branch = "dev"
|
|
||||||
# source = "github.com/myfork/project2"
|
|
||||||
#
|
|
||||||
# [[override]]
|
|
||||||
# name = "github.com/x/y"
|
|
||||||
# version = "2.4.0"
|
|
||||||
#
|
|
||||||
# [prune]
|
|
||||||
# non-go = false
|
|
||||||
# go-tests = true
|
|
||||||
# unused-packages = true
|
|
||||||
|
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/cjbassi/termui"
|
name = "github.com/cjbassi/termui"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
name = "github.com/docopt/docopt-go"
|
name = "github.com/docopt/docopt-go"
|
||||||
version = "0.6.2"
|
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/shirou/gopsutil"
|
name = "github.com/shirou/gopsutil"
|
||||||
|
7
vendor/github.com/docopt/docopt-go/.travis.yml
generated
vendored
7
vendor/github.com/docopt/docopt-go/.travis.yml
generated
vendored
@ -7,15 +7,17 @@ language: go
|
|||||||
go:
|
go:
|
||||||
- 1.4
|
- 1.4
|
||||||
- 1.5
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- 1.7
|
||||||
|
- 1.8
|
||||||
|
- 1.9
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- go get golang.org/x/tools/cmd/vet
|
|
||||||
- go get golang.org/x/tools/cmd/cover
|
- go get golang.org/x/tools/cmd/cover
|
||||||
- go get github.com/golang/lint/golint
|
|
||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@ -23,7 +25,6 @@ install:
|
|||||||
|
|
||||||
script:
|
script:
|
||||||
- go vet -x ./...
|
- go vet -x ./...
|
||||||
- $HOME/gopath/bin/golint ./...
|
|
||||||
- go test -v ./...
|
- go test -v ./...
|
||||||
- go test -covermode=count -coverprofile=profile.cov .
|
- go test -covermode=count -coverprofile=profile.cov .
|
||||||
|
|
||||||
|
1
vendor/github.com/docopt/docopt-go/LICENSE
generated
vendored
1
vendor/github.com/docopt/docopt-go/LICENSE
generated
vendored
@ -1,6 +1,7 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2013 Keith Batten
|
Copyright (c) 2013 Keith Batten
|
||||||
|
Copyright (c) 2016 David Irvine
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
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
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
80
vendor/github.com/docopt/docopt-go/README.md
generated
vendored
80
vendor/github.com/docopt/docopt-go/README.md
generated
vendored
@ -2,11 +2,10 @@ docopt-go
|
|||||||
=========
|
=========
|
||||||
|
|
||||||
[](https://travis-ci.org/docopt/docopt.go)
|
[](https://travis-ci.org/docopt/docopt.go)
|
||||||
[](https://coveralls.io/r/docopt/docopt.go)
|
[](https://coveralls.io/github/docopt/docopt.go)
|
||||||
[](https://godoc.org/github.com/docopt/docopt.go)
|
[](https://godoc.org/github.com/docopt/docopt.go)
|
||||||
|
|
||||||
An implementation of [docopt](http://docopt.org/) in the
|
An implementation of [docopt](http://docopt.org/) in the [Go](http://golang.org/) programming language.
|
||||||
[Go](http://golang.org/) programming language.
|
|
||||||
|
|
||||||
**docopt** helps you create *beautiful* command-line interfaces easily:
|
**docopt** helps you create *beautiful* command-line interfaces easily:
|
||||||
|
|
||||||
@ -36,24 +35,22 @@ Options:
|
|||||||
--moored Moored (anchored) mine.
|
--moored Moored (anchored) mine.
|
||||||
--drifting Drifting mine.`
|
--drifting Drifting mine.`
|
||||||
|
|
||||||
arguments, _ := docopt.Parse(usage, nil, true, "Naval Fate 2.0", false)
|
arguments, _ := docopt.ParseDoc(usage)
|
||||||
fmt.Println(arguments)
|
fmt.Println(arguments)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**docopt** parses command-line arguments based on a help message. Don't
|
**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.
|
||||||
write parser code: a good help message already has all the necessary
|
|
||||||
information in it.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
⚠ Use the alias “docopt-go”. To use docopt in your Go code:
|
⚠ Use the alias "docopt-go". To use docopt in your Go code:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/docopt/docopt-go"
|
import "github.com/docopt/docopt-go"
|
||||||
```
|
```
|
||||||
|
|
||||||
To install docopt according to your `$GOPATH`:
|
To install docopt in your `$GOPATH`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ go get github.com/docopt/docopt-go
|
$ go get github.com/docopt/docopt-go
|
||||||
@ -61,28 +58,59 @@ $ go get github.com/docopt/docopt-go
|
|||||||
|
|
||||||
## API
|
## 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
|
```go
|
||||||
func Parse(doc string, argv []string, help bool, version string,
|
docopt.ParseDoc(usage)
|
||||||
optionsFirst bool, exit ...bool) (map[string]interface{}, error)
|
|
||||||
```
|
```
|
||||||
Parse `argv` based on the command-line interface described in `doc`.
|
|
||||||
|
|
||||||
Given a conventional command-line help message, docopt creates a parser and
|
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:
|
||||||
processes the arguments. See
|
|
||||||
https://github.com/docopt/docopt#help-message-format for a description of the
|
|
||||||
help message format. If `argv` is `nil`, `os.Args[1:]` is used.
|
|
||||||
|
|
||||||
docopt returns a map of option names to the values parsed from `argv`, and an
|
```go
|
||||||
error or `nil`.
|
docopt.ParseArgs(usage, argv, "1.2.3")
|
||||||
|
```
|
||||||
|
|
||||||
More documentation for docopt is available at
|
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.
|
||||||
[GoDoc.org](https://godoc.org/github.com/docopt/docopt.go).
|
|
||||||
|
|
||||||
## Testing
|
```go
|
||||||
|
parser := &docopt.Parser{
|
||||||
|
HelpHandler: docopt.PrintHelpOnly,
|
||||||
|
OptionsFirst: true,
|
||||||
|
}
|
||||||
|
opts, err := parser.ParseArgs(usage, argv, "")
|
||||||
|
```
|
||||||
|
|
||||||
All tests from the Python version are implemented and passing
|
In particular, setting your own custom `HelpHandler` function makes unit testing your own docs with example command line invocations much more enjoyable.
|
||||||
at [Travis CI](https://travis-ci.org/docopt/docopt.go). New
|
|
||||||
language-agnostic tests have been added
|
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:
|
||||||
to [test_golang.docopt](test_golang.docopt).
|
|
||||||
|
```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`.
|
To run tests for docopt-go, use `go test`.
|
||||||
|
49
vendor/github.com/docopt/docopt-go/doc.go
generated
vendored
Normal file
49
vendor/github.com/docopt/docopt-go/doc.go
generated
vendored
Normal 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
|
830
vendor/github.com/docopt/docopt-go/docopt.go
generated
vendored
830
vendor/github.com/docopt/docopt-go/docopt.go
generated
vendored
@ -1,71 +1,113 @@
|
|||||||
// Licensed under terms of MIT license (see LICENSE-MIT)
|
// Licensed under terms of MIT license (see LICENSE-MIT)
|
||||||
// Copyright (c) 2013 Keith Batten, kbatten@gmail.com
|
// Copyright (c) 2013 Keith Batten, kbatten@gmail.com
|
||||||
|
// Copyright (c) 2016 David Irvine
|
||||||
|
|
||||||
/*
|
|
||||||
Package docopt parses command-line arguments based on a help message.
|
|
||||||
|
|
||||||
⚠ Use the alias “docopt-go”:
|
|
||||||
import "github.com/docopt/docopt-go"
|
|
||||||
or
|
|
||||||
$ go get github.com/docopt/docopt-go
|
|
||||||
*/
|
|
||||||
package docopt
|
package docopt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
type Parser struct {
|
||||||
Parse `argv` based on the command-line interface described in `doc`.
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
Given a conventional command-line help message, docopt creates a parser and
|
var PrintHelpAndExit = func(err error, usage string) {
|
||||||
processes the arguments. See
|
if err != nil {
|
||||||
https://github.com/docopt/docopt#help-message-format for a description of the
|
fmt.Fprintln(os.Stderr, usage)
|
||||||
help message format. If `argv` is `nil`, `os.Args[1:]` is used.
|
os.Exit(1)
|
||||||
|
} else {
|
||||||
|
fmt.Println(usage)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
docopt returns a map of option names to the values parsed from `argv`, and an
|
var PrintHelpOnly = func(err error, usage string) {
|
||||||
error or `nil`.
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, usage)
|
||||||
|
} else {
|
||||||
|
fmt.Println(usage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Set `help` to `false` to disable automatic help messages on `-h` or `--help`.
|
var NoHelpHandler = func(err error, usage string) {}
|
||||||
If `version` is a non-empty string, it will be printed when `--version` is
|
|
||||||
specified. Set `optionsFirst` to `true` to require that options always come
|
|
||||||
before positional arguments; otherwise they can overlap.
|
|
||||||
|
|
||||||
By default, docopt calls `os.Exit(0)` if it handled a built-in option such as
|
var DefaultParser = &Parser{
|
||||||
`-h` or `--version`. If the user errored with a wrong command or options,
|
HelpHandler: PrintHelpAndExit,
|
||||||
docopt exits with a return code of 1. To stop docopt from calling `os.Exit()`
|
OptionsFirst: false,
|
||||||
and to handle your own return codes, pass an optional last parameter of `false`
|
SkipHelpFlags: false,
|
||||||
for `exit`.
|
}
|
||||||
*/
|
|
||||||
func Parse(doc string, argv []string, help bool, version string,
|
// ParseDoc parses os.Args[1:] based on the interface described in doc, using the default parser options.
|
||||||
optionsFirst bool, exit ...bool) (map[string]interface{}, error) {
|
func ParseDoc(doc string) (Opts, error) {
|
||||||
// if "false" was the (optional) last arg, don't call os.Exit()
|
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
|
exitOk := true
|
||||||
if len(exit) > 0 {
|
if len(exit) > 0 {
|
||||||
exitOk = exit[0]
|
exitOk = exit[0]
|
||||||
}
|
}
|
||||||
args, output, err := parse(doc, argv, help, version, optionsFirst)
|
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 {
|
if _, ok := err.(*UserError); ok {
|
||||||
// the user gave us bad input
|
// the user gave us bad input
|
||||||
fmt.Fprintln(os.Stderr, output)
|
p.HelpHandler(err, output)
|
||||||
if exitOk {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
} else if len(output) > 0 && err == nil {
|
} else if len(output) > 0 && err == nil {
|
||||||
// the user asked for help or `--version`
|
// the user asked for help or --version
|
||||||
fmt.Println(output)
|
p.HelpHandler(err, output)
|
||||||
if exitOk {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return args, err
|
return args, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// parse and return a map of args, output and all errors
|
// 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) {
|
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 {
|
if argv == nil && len(os.Args) > 1 {
|
||||||
@ -484,39 +526,6 @@ func parseShorts(tokens *tokenList, options *patternList) (patternList, error) {
|
|||||||
return parsed, nil
|
return parsed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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 formalUsage(section string) (string, error) {
|
func formalUsage(section string) (string, error) {
|
||||||
_, _, section = stringPartition(section, ":") // drop "usage:"
|
_, _, section = stringPartition(section, ":") // drop "usage:"
|
||||||
pu := strings.Fields(section)
|
pu := strings.Fields(section)
|
||||||
@ -556,665 +565,6 @@ func extras(help bool, version string, options patternList, doc string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
type tokenList struct {
|
|
||||||
tokens []string
|
|
||||||
errorFunc func(string, ...interface{}) error
|
|
||||||
err errorType
|
|
||||||
}
|
|
||||||
type token string
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func stringPartition(s, sep string) (string, string, string) {
|
func stringPartition(s, sep string) (string, string, string) {
|
||||||
sepPos := strings.Index(s, sep)
|
sepPos := strings.Index(s, sep)
|
||||||
if sepPos == -1 { // no seperator found
|
if sepPos == -1 { // no seperator found
|
||||||
@ -1223,17 +573,3 @@ func stringPartition(s, sep string) (string, string, string) {
|
|||||||
split := strings.SplitN(s, sep, 2)
|
split := strings.SplitN(s, sep, 2)
|
||||||
return split[0], sep, split[1]
|
return split[0], sep, split[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
49
vendor/github.com/docopt/docopt-go/error.go
generated
vendored
Normal file
49
vendor/github.com/docopt/docopt-go/error.go
generated
vendored
Normal 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
264
vendor/github.com/docopt/docopt-go/opts.go
generated
vendored
Normal 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
550
vendor/github.com/docopt/docopt-go/pattern.go
generated
vendored
Normal 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
|
||||||
|
}
|
126
vendor/github.com/docopt/docopt-go/token.go
generated
vendored
Normal file
126
vendor/github.com/docopt/docopt-go/token.go
generated
vendored
Normal 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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user