nix-archive-1(type directoryentry(namesharenode(type directoryentry(namedocnode(type directoryentry(name.go-github-com-docopt-docopt-go-0.6.2-0.ee0de3bnode(type directoryentry(nameLICENSEnode(typeregularcontentsWThe 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. ))))))))entry(namesrcnode(type directoryentry(name github.comnode(type directoryentry(namedocoptnode(type directoryentry(name docopt-gonode(type directoryentry(name .gitignorenode(typeregularcontents# 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 ))entry(name .travis.ymlnode(typeregularcontents€# 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 ))entry(nameLICENSEnode(typeregularcontentsWThe 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. ))entry(name README.mdnode(typeregularcontents+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 ... naval_fate ship move [--speed=] naval_fate ship shoot naval_fate mine (set|remove) [--moored|--drifting] naval_fate -h | --help naval_fate --version Options: -h --help Show this screen. --version Show version. --speed= 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("") ``` 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:""` 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`. ))entry(namedoc.gonode(typeregularcontentsą/* 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("") 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:""` Tries int `docopt:"-n"` Force bool // Gets the value of --force } opts.Bind(&config) */ package docopt ))entry(name docopt.gonode(typeregularcontents<// 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] } ))entry(namedocopt_test.gonode(typeregularcontents‚¤/* Based of off docopt.py: https://github.com/docopt/docopt Licensed under terms of MIT license (see LICENSE-MIT) Copyright (c) 2013 Keith Batten, kbatten@gmail.com */ package docopt import ( "bytes" "encoding/json" "fmt" "io/ioutil" "os" "reflect" "regexp" "strings" "testing" ) var testParser = &Parser{HelpHandler: NoHelpHandler} func TestPatternFlat(t *testing.T) { q := patternList{ newArgument("N", nil), newOption("-a", "", 0, false), newArgument("M", nil)} p, err := newRequired( newOneOrMore(newArgument("N", nil)), newOption("-a", "", 0, false), newArgument("M", nil)).flat(patternDefault) if reflect.DeepEqual(p, q) != true { t.Error(err) } q = patternList{newOptionsShortcut()} p, err = newRequired( newOptional(newOptionsShortcut()), newOptional(newOption("-a", "", 0, false))).flat(patternOptionSSHORTCUT) if reflect.DeepEqual(p, q) != true { t.Error(err) } return } func TestOption(t *testing.T) { if !parseOption("-h").eq(newOption("-h", "", 0, false)) { t.Fail() } if !parseOption("--help").eq(newOption("", "--help", 0, false)) { t.Fail() } if !parseOption("-h --help").eq(newOption("-h", "--help", 0, false)) { t.Fail() } if !parseOption("-h, --help").eq(newOption("-h", "--help", 0, false)) { t.Fail() } if !parseOption("-h TOPIC").eq(newOption("-h", "", 1, false)) { t.Fail() } if !parseOption("--help TOPIC").eq(newOption("", "--help", 1, false)) { t.Fail() } if !parseOption("-h TOPIC --help TOPIC").eq(newOption("-h", "--help", 1, false)) { t.Fail() } if !parseOption("-h TOPIC, --help TOPIC").eq(newOption("-h", "--help", 1, false)) { t.Fail() } if !parseOption("-h TOPIC, --help=TOPIC").eq(newOption("-h", "--help", 1, false)) { t.Fail() } if !parseOption("-h Description...").eq(newOption("-h", "", 0, false)) { t.Fail() } if !parseOption("-h --help Description...").eq(newOption("-h", "--help", 0, false)) { t.Fail() } if !parseOption("-h TOPIC Description...").eq(newOption("-h", "", 1, false)) { t.Fail() } if !parseOption(" -h").eq(newOption("-h", "", 0, false)) { t.Fail() } if !parseOption("-h TOPIC Description... [default: 2]").eq(newOption("-h", "", 1, "2")) { t.Fail() } if !parseOption("-h TOPIC Descripton... [default: topic-1]").eq(newOption("-h", "", 1, "topic-1")) { t.Fail() } if !parseOption("--help=TOPIC ... [default: 3.14]").eq(newOption("", "--help", 1, "3.14")) { t.Fail() } if !parseOption("-h, --help=DIR ... [default: ./]").eq(newOption("-h", "--help", 1, "./")) { t.Fail() } if !parseOption("-h TOPIC Descripton... [dEfAuLt: 2]").eq(newOption("-h", "", 1, "2")) { t.Fail() } return } func TestOptionName(t *testing.T) { if newOption("-h", "", 0, false).name != "-h" { t.Fail() } if newOption("-h", "--help", 0, false).name != "--help" { t.Fail() } if newOption("", "--help", 0, false).name != "--help" { t.Fail() } return } func TestCommands(t *testing.T) { if v, err := testParser.ParseArgs("Usage: prog add", []string{"add"}, ""); reflect.DeepEqual(v, Opts{"add": true}) != true { t.Error(err) } if v, err := testParser.ParseArgs("Usage: prog [add]", []string{}, ""); reflect.DeepEqual(v, Opts{"add": false}) != true { t.Error(err) } if v, err := testParser.ParseArgs("Usage: prog [add]", []string{"add"}, ""); reflect.DeepEqual(v, Opts{"add": true}) != true { t.Error(err) } if v, err := testParser.ParseArgs("Usage: prog (add|rm)", []string{"add"}, ""); reflect.DeepEqual(v, Opts{"add": true, "rm": false}) != true { t.Error(err) } if v, err := testParser.ParseArgs("Usage: prog (add|rm)", []string{"rm"}, ""); reflect.DeepEqual(v, Opts{"add": false, "rm": true}) != true { t.Error(err) } if v, err := testParser.ParseArgs("Usage: prog a b", []string{"a", "b"}, ""); reflect.DeepEqual(v, Opts{"a": true, "b": true}) != true { t.Error(err) } _, err := testParser.ParseArgs("Usage: prog a b", []string{"b", "a"}, "") if _, ok := err.(*UserError); !ok { t.Error(err) } return } func TestFormalUsage(t *testing.T) { doc := ` Usage: prog [-hv] ARG prog N M prog is a program` usage := parseSection("usage:", doc)[0] if usage != "Usage: prog [-hv] ARG\n prog N M" { t.FailNow() } formal, err := formalUsage(usage) if err != nil { t.Fatal(err) } if formal != "( [-hv] ARG ) | ( N M )" { t.Fail() } return } func TestParseArgv(t *testing.T) { o := patternList{ newOption("-h", "", 0, false), newOption("-v", "--verbose", 0, false), newOption("-f", "--file", 1, false), } p, err := parseArgv(tokenListFromString(""), &o, false) q := patternList{} if reflect.DeepEqual(p, q) != true { t.Error(err) } p, err = parseArgv(tokenListFromString("-h"), &o, false) q = patternList{newOption("-h", "", 0, true)} if reflect.DeepEqual(p, q) != true { t.Error(err) } p, err = parseArgv(tokenListFromString("-h --verbose"), &o, false) q = patternList{ newOption("-h", "", 0, true), newOption("-v", "--verbose", 0, true), } if reflect.DeepEqual(p, q) != true { t.Error(err) } p, err = parseArgv(tokenListFromString("-h --file f.txt"), &o, false) q = patternList{ newOption("-h", "", 0, true), newOption("-f", "--file", 1, "f.txt"), } if reflect.DeepEqual(p, q) != true { t.Error(err) } p, err = parseArgv(tokenListFromString("-h --file f.txt arg"), &o, false) q = patternList{ newOption("-h", "", 0, true), newOption("-f", "--file", 1, "f.txt"), newArgument("", "arg"), } if reflect.DeepEqual(p, q) != true { t.Error(err) } p, err = parseArgv(tokenListFromString("-h --file f.txt arg arg2"), &o, false) q = patternList{ newOption("-h", "", 0, true), newOption("-f", "--file", 1, "f.txt"), newArgument("", "arg"), newArgument("", "arg2"), } if reflect.DeepEqual(p, q) != true { t.Error(err) } p, err = parseArgv(tokenListFromString("-h arg -- -v"), &o, false) q = patternList{ newOption("-h", "", 0, true), newArgument("", "arg"), newArgument("", "--"), newArgument("", "-v"), } if reflect.DeepEqual(p, q) != true { t.Error(err) } } func TestParsePattern(t *testing.T) { o := patternList{ newOption("-h", "", 0, false), newOption("-v", "--verbose", 0, false), newOption("-f", "--file", 1, false), } p, err := parsePattern("[ -h ]", &o) q := newRequired(newOptional(newOption("-h", "", 0, false))) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("[ ARG ... ]", &o) q = newRequired(newOptional( newOneOrMore( newArgument("ARG", nil)))) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("[ -h | -v ]", &o) q = newRequired( newOptional( newEither( newOption("-h", "", 0, false), newOption("-v", "--verbose", 0, false)))) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("( -h | -v [ --file ] )", &o) q = newRequired( newRequired( newEither( newOption("-h", "", 0, false), newRequired( newOption("-v", "--verbose", 0, false), newOptional( newOption("-f", "--file", 1, nil)))))) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("(-h|-v[--file=]N...)", &o) q = newRequired( newRequired( newEither( newOption("-h", "", 0, false), newRequired( newOption("-v", "--verbose", 0, false), newOptional( newOption("-f", "--file", 1, nil)), newOneOrMore( newArgument("N", nil)))))) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("(N [M | (K | L)] | O P)", &o) q = newRequired( newRequired( newEither( newRequired( newArgument("N", nil), newOptional( newEither( newArgument("M", nil), newRequired( newEither( newArgument("K", nil), newArgument("L", nil)))))), newRequired( newArgument("O", nil), newArgument("P", nil))))) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("[ -h ] [N]", &o) q = newRequired( newOptional( newOption("-h", "", 0, false)), newOptional( newArgument("N", nil))) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("[options]", &o) q = newRequired( newOptional( newOptionsShortcut())) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("[options] A", &o) q = newRequired( newOptional( newOptionsShortcut()), newArgument("A", nil)) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("-v [options]", &o) q = newRequired( newOption("-v", "--verbose", 0, false), newOptional( newOptionsShortcut())) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("ADD", &o) q = newRequired(newArgument("ADD", nil)) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("", &o) q = newRequired(newArgument("", nil)) if p.eq(q) != true { t.Error(err) } p, err = parsePattern("add", &o) q = newRequired(newCommand("add", false)) if p.eq(q) != true { t.Error(err) } } func TestOptionMatch(t *testing.T) { v, w, x := newOption("-a", "", 0, false).match( &patternList{newOption("-a", "", 0, true)}, nil) y := patternList{newOption("-a", "", 0, true)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newOption("-a", "", 0, false).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newOption("-a", "", 0, false).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newOption("-a", "", 0, false).match( &patternList{newArgument("N", nil)}, nil) y = patternList{newArgument("N", nil)} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newOption("-a", "", 0, false).match( &patternList{ newOption("-x", "", 0, false), newOption("-a", "", 0, false), newArgument("N", nil)}, nil) y = patternList{ newOption("-x", "", 0, false), newArgument("N", nil)} z := patternList{newOption("-a", "", 0, false)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOption("-a", "", 0, false).match( &patternList{ newOption("-a", "", 0, true), newOption("-a", "", 0, false)}, nil) y = patternList{newOption("-a", "", 0, false)} z = patternList{newOption("-a", "", 0, true)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } } func TestArgumentMatch(t *testing.T) { v, w, x := newArgument("N", nil).match( &patternList{newArgument("N", 9)}, nil) y := patternList{newArgument("N", 9)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newArgument("N", nil).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newArgument("N", nil).match( &patternList{newOption("-x", "", 0, false), newOption("-a", "", 0, false), newArgument("", 5)}, nil) y = patternList{newOption("-x", "", 0, false), newOption("-a", "", 0, false)} z := patternList{newArgument("N", 5)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newArgument("N", nil).match( &patternList{newArgument("", 9), newArgument("", 0)}, nil) y = patternList{newArgument("", 0)} z = patternList{newArgument("N", 9)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } } func TestCommandMatch(t *testing.T) { v, w, x := newCommand("c", false).match( &patternList{newArgument("", "c")}, nil) y := patternList{newCommand("c", true)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newCommand("c", false).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newCommand("c", false).match( &patternList{ newOption("-x", "", 0, false), newOption("-a", "", 0, false), newArgument("", "c")}, nil) y = patternList{newOption("-x", "", 0, false), newOption("-a", "", 0, false)} z := patternList{newCommand("c", true)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newEither( newCommand("add", false), newCommand("rm", false)).match( &patternList{newArgument("", "rm")}, nil) y = patternList{newCommand("rm", true)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } } func TestOptionalMatch(t *testing.T) { v, w, x := newOptional(newOption("-a", "", 0, false)).match( &patternList{newOption("-a", "", 0, false)}, nil) y := patternList{newOption("-a", "", 0, false)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newOptional(newOption("-a", "", 0, false)).match( &patternList{}, nil) if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newOptional(newOption("-a", "", 0, false)).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newOptional(newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match( &patternList{newOption("-a", "", 0, false)}, nil) y = patternList{newOption("-a", "", 0, false)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newOptional(newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match( &patternList{newOption("-b", "", 0, false)}, nil) y = patternList{newOption("-b", "", 0, false)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newOptional(newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newOptional(newArgument("N", nil)).match( &patternList{newArgument("", 9)}, nil) y = patternList{newArgument("N", 9)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newOptional(newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match( &patternList{newOption("-b", "", 0, false), newOption("-x", "", 0, false), newOption("-a", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} z := patternList{newOption("-a", "", 0, false), newOption("-b", "", 0, false)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } } func TestRequiredMatch(t *testing.T) { v, w, x := newRequired(newOption("-a", "", 0, false)).match( &patternList{newOption("-a", "", 0, false)}, nil) y := patternList{newOption("-a", "", 0, false)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newRequired(newOption("-a", "", 0, false)).match(&patternList{}, nil) if v != false || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newRequired(newOption("-a", "", 0, false)).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } v, w, x = newRequired(newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match( &patternList{newOption("-a", "", 0, false)}, nil) y = patternList{newOption("-a", "", 0, false)} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, patternList{}) != true { t.Fail() } } func TestEitherMatch(t *testing.T) { v, w, x := newEither( newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match( &patternList{newOption("-a", "", 0, false)}, nil) y := patternList{newOption("-a", "", 0, false)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newEither( newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match(&patternList{ newOption("-a", "", 0, false), newOption("-b", "", 0, false)}, nil) y = patternList{newOption("-b", "", 0, false)} z := patternList{newOption("-a", "", 0, false)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newEither( newOption("-a", "", 0, false), newOption("-b", "", 0, false)).match(&patternList{ newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} z = patternList{} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newEither( newOption("-a", "", 0, false), newOption("-b", "", 0, false), newOption("-c", "", 0, false)).match(&patternList{ newOption("-x", "", 0, false), newOption("-b", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} z = patternList{newOption("-b", "", 0, false)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newEither( newArgument("M", nil), newRequired(newArgument("N", nil), newArgument("M", nil))).match(&patternList{ newArgument("", 1), newArgument("", 2)}, nil) y = patternList{} z = patternList{newArgument("N", 1), newArgument("M", 2)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } } func TestOneOrMoreMatch(t *testing.T) { v, w, x := newOneOrMore(newArgument("N", nil)).match( &patternList{newArgument("", 9)}, nil) y := patternList{newArgument("N", 9)} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } v, w, x = newOneOrMore(newArgument("N", nil)).match( &patternList{}, nil) y = patternList{} z := patternList{} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOneOrMore(newArgument("N", nil)).match( &patternList{newOption("-x", "", 0, false)}, nil) y = patternList{newOption("-x", "", 0, false)} z = patternList{} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOneOrMore(newArgument("N", nil)).match( &patternList{newArgument("", 9), newArgument("", 8)}, nil) y = patternList{} z = patternList{newArgument("N", 9), newArgument("N", 8)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOneOrMore(newArgument("N", nil)).match(&patternList{ newArgument("", 9), newOption("-x", "", 0, false), newArgument("", 8)}, nil) y = patternList{newOption("-x", "", 0, false)} z = patternList{newArgument("N", 9), newArgument("N", 8)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{ newOption("-a", "", 0, false), newArgument("", 8), newOption("-a", "", 0, false)}, nil) y = patternList{newArgument("", 8)} z = patternList{newOption("-a", "", 0, false), newOption("-a", "", 0, false)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOneOrMore(newOption("-a", "", 0, false)).match(&patternList{ newArgument("", 8), newOption("-x", "", 0, false)}, nil) y = patternList{newArgument("", 8), newOption("-x", "", 0, false)} z = patternList{} if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOneOrMore(newRequired(newOption("-a", "", 0, false), newArgument("N", nil))).match(&patternList{ newOption("-a", "", 0, false), newArgument("", 1), newOption("-x", "", 0, false), newOption("-a", "", 0, false), newArgument("", 2)}, nil) y = patternList{newOption("-x", "", 0, false)} z = patternList{newOption("-a", "", 0, false), newArgument("N", 1), newOption("-a", "", 0, false), newArgument("N", 2)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } v, w, x = newOneOrMore(newOptional(newArgument("N", nil))).match( &patternList{newArgument("", 9)}, nil) y = patternList{} z = patternList{newArgument("N", 9)} if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } } func TestListArgumentMatch(t *testing.T) { p := newRequired( newArgument("N", nil), newArgument("N", nil)) p.fix() v, w, x := p.match(&patternList{newArgument("", "1"), newArgument("", "2")}, nil) y := patternList{newArgument("N", []string{"1", "2"})} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } p = newOneOrMore(newArgument("N", nil)) p.fix() v, w, x = p.match(&patternList{newArgument("", "1"), newArgument("", "2"), newArgument("", "3")}, nil) y = patternList{newArgument("N", []string{"1", "2", "3"})} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } p = newRequired(newArgument("N", nil), newOneOrMore(newArgument("N", nil))) p.fix() v, w, x = p.match(&patternList{ newArgument("", "1"), newArgument("", "2"), newArgument("", "3")}, nil) y = patternList{newArgument("N", []string{"1", "2", "3"})} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } p = newRequired(newArgument("N", nil), newRequired(newArgument("N", nil))) p.fix() v, w, x = p.match(&patternList{ newArgument("", "1"), newArgument("", "2")}, nil) y = patternList{newArgument("N", []string{"1", "2"})} if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } } func TestBasicPatternMatching(t *testing.T) { // ( -a N [ -x Z ] ) p := newRequired( newOption("-a", "", 0, false), newArgument("N", nil), newOptional( newOption("-x", "", 0, false), newArgument("Z", nil))) // -a N q := patternList{newOption("-a", "", 0, false), newArgument("", 9)} y := patternList{newOption("-a", "", 0, false), newArgument("N", 9)} v, w, x := p.match(&q, nil) if v != true || reflect.DeepEqual(*w, patternList{}) != true || reflect.DeepEqual(*x, y) != true { t.Fail() } // -a -x N Z q = patternList{newOption("-a", "", 0, false), newOption("-x", "", 0, false), newArgument("", 9), newArgument("", 5)} y = patternList{} z := patternList{newOption("-a", "", 0, false), newArgument("N", 9), newOption("-x", "", 0, false), newArgument("Z", 5)} v, w, x = p.match(&q, nil) if v != true || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } // -x N Z # BZZ! q = patternList{newOption("-x", "", 0, false), newArgument("", 9), newArgument("", 5)} y = patternList{newOption("-x", "", 0, false), newArgument("", 9), newArgument("", 5)} z = patternList{} v, w, x = p.match(&q, nil) if v != false || reflect.DeepEqual(*w, y) != true || reflect.DeepEqual(*x, z) != true { t.Fail() } } func TestPatternEither(t *testing.T) { p := newOption("-a", "", 0, false).transform() q := newEither(newRequired( newOption("-a", "", 0, false))) if p.eq(q) != true { t.Fail() } p = newArgument("A", nil).transform() q = newEither(newRequired( newArgument("A", nil))) if p.eq(q) != true { t.Fail() } p = newRequired( newEither( newOption("-a", "", 0, false), newOption("-b", "", 0, false)), newOption("-c", "", 0, false)).transform() q = newEither( newRequired( newOption("-a", "", 0, false), newOption("-c", "", 0, false)), newRequired( newOption("-b", "", 0, false), newOption("-c", "", 0, false))) if p.eq(q) != true { t.Fail() } p = newOptional(newOption("-a", "", 0, false), newEither(newOption("-b", "", 0, false), newOption("-c", "", 0, false))).transform() q = newEither( newRequired( newOption("-b", "", 0, false), newOption("-a", "", 0, false)), newRequired( newOption("-c", "", 0, false), newOption("-a", "", 0, false))) if p.eq(q) != true { t.Fail() } p = newEither(newOption("-x", "", 0, false), newEither(newOption("-y", "", 0, false), newOption("-z", "", 0, false))).transform() q = newEither( newRequired(newOption("-x", "", 0, false)), newRequired(newOption("-y", "", 0, false)), newRequired(newOption("-z", "", 0, false))) if p.eq(q) != true { t.Fail() } p = newOneOrMore(newArgument("N", nil), newArgument("M", nil)).transform() q = newEither( newRequired(newArgument("N", nil), newArgument("M", nil), newArgument("N", nil), newArgument("M", nil))) if p.eq(q) != true { t.Fail() } } func TestPatternFixRepeatingArguments(t *testing.T) { p := newOption("-a", "", 0, false) p.fixRepeatingArguments() if p.eq(newOption("-a", "", 0, false)) != true { t.Fail() } p = newArgument("N", nil) p.fixRepeatingArguments() if p.eq(newArgument("N", nil)) != true { t.Fail() } p = newRequired( newArgument("N", nil), newArgument("N", nil)) q := newRequired( newArgument("N", []string{}), newArgument("N", []string{})) p.fixRepeatingArguments() if p.eq(q) != true { t.Fail() } p = newEither( newArgument("N", nil), newOneOrMore(newArgument("N", nil))) q = newEither( newArgument("N", []string{}), newOneOrMore(newArgument("N", []string{}))) p.fix() if p.eq(q) != true { t.Fail() } } func TestSet(t *testing.T) { p := newArgument("N", nil) q := newArgument("N", nil) if reflect.DeepEqual(p, q) != true { t.Fail() } pl := patternList{newArgument("N", nil), newArgument("N", nil)} ql := patternList{newArgument("N", nil)} if reflect.DeepEqual(pl.unique(), ql.unique()) != true { t.Fail() } } func TestPatternFixIdentities1(t *testing.T) { p := newRequired( newArgument("N", nil), newArgument("N", nil)) if len(p.children) < 2 { t.FailNow() } if p.children[0].eq(p.children[1]) != true { t.Fail() } if p.children[0] == p.children[1] { t.Fail() } p.fixIdentities(nil) if p.children[0] != p.children[1] { t.Fail() } } func TestPatternFixIdentities2(t *testing.T) { p := newRequired( newOptional( newArgument("X", nil), newArgument("N", nil)), newArgument("N", nil)) if len(p.children) < 2 { t.FailNow() } if len(p.children[0].children) < 2 { t.FailNow() } if p.children[0].children[1].eq(p.children[1]) != true { t.Fail() } if p.children[0].children[1] == p.children[1] { t.Fail() } p.fixIdentities(nil) if p.children[0].children[1] != p.children[1] { t.Fail() } } func TestLongOptionsErrorHandling(t *testing.T) { _, err := testParser.ParseArgs("Usage: prog", []string{"--non-existent"}, "") if _, ok := err.(*UserError); !ok { t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err)) } _, err = testParser.ParseArgs("Usage: prog [--version --verbose]\nOptions: --version\n --verbose", []string{"--ver"}, "") if _, ok := err.(*UserError); !ok { t.Error(err) } _, err = testParser.ParseArgs("Usage: prog --long\nOptions: --long ARG", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(err) } _, err = testParser.ParseArgs("Usage: prog --long ARG\nOptions: --long ARG", []string{"--long"}, "") if _, ok := err.(*UserError); !ok { t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err)) } _, err = testParser.ParseArgs("Usage: prog --long=ARG\nOptions: --long", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(err) } _, err = testParser.ParseArgs("Usage: prog --long\nOptions: --long", []string{}, "--long=ARG") if _, ok := err.(*UserError); !ok { t.Error(err) } } func TestShortOptionsErrorHandling(t *testing.T) { _, err := testParser.ParseArgs("Usage: prog -x\nOptions: -x this\n -x that", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(fmt.Sprintf("(%s) %s", reflect.TypeOf(err), err)) } _, err = testParser.ParseArgs("Usage: prog", []string{"-x"}, "") if _, ok := err.(*UserError); !ok { t.Error(err) } _, err = testParser.ParseArgs("Usage: prog -o\nOptions: -o ARG", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(err) } _, err = testParser.ParseArgs("Usage: prog -o ARG\nOptions: -o ARG", []string{"-o"}, "") if _, ok := err.(*UserError); !ok { t.Error(err) } } func TestMatchingParen(t *testing.T) { _, err := testParser.ParseArgs("Usage: prog [a [b]", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(err) } _, err = testParser.ParseArgs("Usage: prog [a [b] ] c )", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(err) } } func TestAllowDoubleDash(t *testing.T) { if v, err := testParser.ParseArgs("usage: prog [-o] [--] \noptions: -o", []string{"--", "-o"}, ""); reflect.DeepEqual(v, Opts{"-o": false, "": "-o", "--": true}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [-o] [--] \noptions: -o", []string{"-o", "1"}, ""); reflect.DeepEqual(v, Opts{"-o": true, "": "1", "--": false}) != true { t.Error(err) } _, err := testParser.ParseArgs("usage: prog [-o] \noptions:-o", []string{"-o"}, "") if _, ok := err.(*UserError); !ok { //"--" is not allowed; FIXME? t.Error(err) } } func TestDocopt(t *testing.T) { doc := `Usage: prog [-v] A Options: -v Be verbose.` if v, err := testParser.ParseArgs(doc, []string{"arg"}, ""); reflect.DeepEqual(v, Opts{"-v": false, "A": "arg"}) != true { t.Error(err) } if v, err := testParser.ParseArgs(doc, []string{"-v", "arg"}, ""); reflect.DeepEqual(v, Opts{"-v": true, "A": "arg"}) != true { t.Error(err) } doc = `Usage: prog [-vqr] [FILE] prog INPUT OUTPUT prog --help Options: -v print status messages -q report only file names -r show all occurrences of the same error --help ` if v, err := testParser.ParseArgs(doc, []string{"-v", "file.py"}, ""); reflect.DeepEqual(v, Opts{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": "file.py", "INPUT": nil, "OUTPUT": nil}) != true { t.Error(err) } if v, err := testParser.ParseArgs(doc, []string{"-v"}, ""); reflect.DeepEqual(v, Opts{"-v": true, "-q": false, "-r": false, "--help": false, "FILE": nil, "INPUT": nil, "OUTPUT": nil}) != true { t.Error(err) } _, err := testParser.ParseArgs(doc, []string{"-v", "input.py", "output.py"}, "") // does not match if _, ok := err.(*UserError); !ok { t.Error(err) } _, err = testParser.ParseArgs(doc, []string{"--fake"}, "") if _, ok := err.(*UserError); !ok { t.Error(err) } _, output, err := parseOutput(doc, []string{"--hel"}, true, "", false) if err != nil || len(output) == 0 { t.Error(err) } } func TestLanguageErrors(t *testing.T) { _, err := testParser.ParseArgs("no usage with colon here", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(err) } _, err = testParser.ParseArgs("usage: here \n\n and again usage: here", []string{}, "") if _, ok := err.(*LanguageError); !ok { t.Error(err) } } func TestIssue40(t *testing.T) { _, output, err := parseOutput("usage: prog --help-commands | --help", []string{"--help"}, true, "", false) if err != nil || len(output) == 0 { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog --aabb | --aa", []string{"--aa"}, ""); reflect.DeepEqual(v, Opts{"--aabb": false, "--aa": true}) != true { t.Error(err) } } func TestIssue34UnicodeStrings(t *testing.T) { // TODO: see if applicable } func TestCountMultipleFlags(t *testing.T) { if v, err := testParser.ParseArgs("usage: prog [-v]", []string{"-v"}, ""); reflect.DeepEqual(v, Opts{"-v": true}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [-vv]", []string{}, ""); reflect.DeepEqual(v, Opts{"-v": 0}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [-vv]", []string{"-v"}, ""); reflect.DeepEqual(v, Opts{"-v": 1}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [-vv]", []string{"-vv"}, ""); reflect.DeepEqual(v, Opts{"-v": 2}) != true { t.Error(err) } _, err := testParser.ParseArgs("usage: prog [-vv]", []string{"-vvv"}, "") if _, ok := err.(*UserError); !ok { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [-v | -vv | -vvv]", []string{"-vvv"}, ""); reflect.DeepEqual(v, Opts{"-v": 3}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [-v...]", []string{"-vvvvvv"}, ""); reflect.DeepEqual(v, Opts{"-v": 6}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [--ver --ver]", []string{"--ver", "--ver"}, ""); reflect.DeepEqual(v, Opts{"--ver": 2}) != true { t.Error(err) } } func TestAnyOptionsParameter(t *testing.T) { _, err := testParser.ParseArgs("usage: prog [options]", []string{"-foo", "--bar", "--spam=eggs"}, "") if _, ok := err.(*UserError); !ok { t.Fail() } _, err = testParser.ParseArgs("usage: prog [options]", []string{"--foo", "--bar", "--bar"}, "") if _, ok := err.(*UserError); !ok { t.Fail() } _, err = testParser.ParseArgs("usage: prog [options]", []string{"--bar", "--bar", "--bar", "-ffff"}, "") if _, ok := err.(*UserError); !ok { t.Fail() } _, err = testParser.ParseArgs("usage: prog [options]", []string{"--long=arg", "--long=another"}, "") if _, ok := err.(*UserError); !ok { t.Fail() } } func TestDefaultValueForPositionalArguments(t *testing.T) { doc := "Usage: prog [--data=...]\nOptions:\n\t-d --data= Input data [default: x]" if v, err := testParser.ParseArgs(doc, []string{}, ""); reflect.DeepEqual(v, Opts{"--data": []string{"x"}}) != true { t.Error(err) } doc = "Usage: prog [--data=...]\nOptions:\n\t-d --data= Input data [default: x y]" if v, err := testParser.ParseArgs(doc, []string{}, ""); reflect.DeepEqual(v, Opts{"--data": []string{"x", "y"}}) != true { t.Error(err) } doc = "Usage: prog [--data=...]\nOptions:\n\t-d --data= Input data [default: x y]" if v, err := testParser.ParseArgs(doc, []string{"--data=this"}, ""); reflect.DeepEqual(v, Opts{"--data": []string{"this"}}) != true { t.Error(err) } } func TestIssue59(t *testing.T) { if v, err := testParser.ParseArgs("usage: prog --long=", []string{"--long="}, ""); reflect.DeepEqual(v, Opts{"--long": ""}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog -l \noptions: -l ", []string{"-l", ""}, ""); reflect.DeepEqual(v, Opts{"-l": ""}) != true { t.Error(err) } } func TestOptionsFirst(t *testing.T) { if v, err := testParser.ParseArgs("usage: prog [--opt] [...]", []string{"--opt", "this", "that"}, ""); reflect.DeepEqual(v, Opts{"--opt": true, "": []string{"this", "that"}}) != true { t.Error(err) } if v, err := testParser.ParseArgs("usage: prog [--opt] [...]", []string{"this", "that", "--opt"}, ""); reflect.DeepEqual(v, Opts{"--opt": true, "": []string{"this", "that"}}) != true { t.Error(err) } optFirstParser := &Parser{HelpHandler: PrintHelpOnly, OptionsFirst: true} if v, err := optFirstParser.ParseArgs("usage: prog [--opt] [...]", []string{"this", "that", "--opt"}, ""); reflect.DeepEqual(v, Opts{"--opt": false, "": []string{"this", "that", "--opt"}}) != true { t.Error(err) } } func TestIssue68OptionsShortcutDoesNotIncludeOptionsInUsagePattern(t *testing.T) { args, err := testParser.ParseArgs("usage: prog [-ab] [options]\noptions: -x\n -y", []string{"-ax"}, "") if args["-a"] != true { t.Error(err) } if args["-b"] != false { t.Error(err) } if args["-x"] != true { t.Error(err) } if args["-y"] != false { t.Error(err) } } func TestIssue65EvaluateArgvWhenCalledNotWhenImported(t *testing.T) { os.Args = strings.Fields("prog -a") v, err := testParser.ParseArgs("usage: prog [-ab]", nil, "") w := Opts{"-a": true, "-b": false} if reflect.DeepEqual(v, w) != true { t.Error(err) } os.Args = strings.Fields("prog -b") v, err = testParser.ParseArgs("usage: prog [-ab]", nil, "") w = Opts{"-a": false, "-b": true} if reflect.DeepEqual(v, w) != true { t.Error(err) } } func TestIssue71DoubleDashIsNotAValidOptionArgument(t *testing.T) { _, err := testParser.ParseArgs("usage: prog [--log=LEVEL] [--] ...", []string{"--log", "--", "1", "2"}, "") if _, ok := err.(*UserError); !ok { t.Fail() } _, err = testParser.ParseArgs(`usage: prog [-l LEVEL] [--] ... options: -l LEVEL`, []string{"-l", "--", "1", "2"}, "") if _, ok := err.(*UserError); !ok { t.Fail() } } func TestParseSection(t *testing.T) { v := parseSection("usage:", "foo bar fizz buzz") w := []string{} if reflect.DeepEqual(v, w) != true { t.Fail() } v = parseSection("usage:", "usage: prog") w = []string{"usage: prog"} if reflect.DeepEqual(v, w) != true { t.Fail() } v = parseSection("usage:", "usage: -x\n -y") w = []string{"usage: -x\n -y"} if reflect.DeepEqual(v, w) != true { t.Fail() } usage := `usage: this usage:hai usage: this that usage: foo bar PROGRAM USAGE: foo bar usage: ` + "\t" + `too ` + "\t" + `tar Usage: eggs spam BAZZ usage: pit stop` v = parseSection("usage:", usage) w = []string{"usage: this", "usage:hai", "usage: this that", "usage: foo\n bar", "PROGRAM USAGE:\n foo\n bar", "usage:\n\ttoo\n\ttar", "Usage: eggs spam", "usage: pit stop", } if reflect.DeepEqual(v, w) != true { t.Fail() } } func TestIssue126DefaultsNotParsedCorrectlyWhenTabs(t *testing.T) { section := "Options:\n\t--foo= [default: bar]" v := patternList{newOption("", "--foo", 1, "bar")} if reflect.DeepEqual(parseDefaults(section), v) != true { t.Fail() } } // conf file based test cases func TestFileTestcases(t *testing.T) { filenames := []string{"testcases.docopt", "test_golang.docopt"} for _, filename := range filenames { raw, err := ioutil.ReadFile(filename) if err != nil { t.Fatal(err) } tests, err := parseTest(raw) if err != nil { t.Fatal(err) } for _, c := range tests { result, err := testParser.ParseArgs(c.doc, c.argv, "") if _, ok := err.(*UserError); c.userError && !ok { // expected a user-error t.Error("testcase:", c.id, "result:", result) } else if _, ok := err.(*UserError); !c.userError && ok { // unexpected user-error t.Error("testcase:", c.id, "error:", err, "result:", result) } else if reflect.DeepEqual(c.expect, result) != true { t.Error("testcase:", c.id, "result:", result, "expect:", c.expect) } } } } type testcase struct { id int doc string prog string argv []string expect Opts userError bool } func parseTest(raw []byte) ([]testcase, error) { var res []testcase commentPattern := regexp.MustCompile("#.*") raw = commentPattern.ReplaceAll(raw, []byte("")) raw = bytes.TrimSpace(raw) if bytes.HasPrefix(raw, []byte(`"""`)) { raw = raw[3:] } id := 0 for _, fixture := range bytes.Split(raw, []byte(`r"""`)) { doc, _, body := stringPartition(string(fixture), `"""`) for _, cas := range strings.Split(body, "$")[1:] { argvString, _, expectString := stringPartition(strings.TrimSpace(cas), "\n") prog, _, argvString := stringPartition(strings.TrimSpace(argvString), " ") argv := []string{} if len(argvString) > 0 { argv = strings.Fields(argvString) } var expectUntyped interface{} err := json.Unmarshal([]byte(expectString), &expectUntyped) if err != nil { return nil, err } switch expect := expectUntyped.(type) { case string: // user-error res = append(res, testcase{id, doc, prog, argv, nil, true}) case map[string]interface{}: // convert []interface{} values to []string // convert float64 values to int for k, vUntyped := range expect { switch v := vUntyped.(type) { case []interface{}: itemList := make([]string, len(v)) for i, itemUntyped := range v { if item, ok := itemUntyped.(string); ok { itemList[i] = item } } expect[k] = itemList case float64: expect[k] = int(v) } } res = append(res, testcase{id, doc, prog, argv, expect, false}) default: return nil, fmt.Errorf("unhandled json data type") } id++ } } return res, nil } // parseOutput uses a custom parser which also returns the output func parseOutput(doc string, argv []string, help bool, version string, optionsFirst bool) (Opts, string, error) { var output string p := &Parser{ HelpHandler: func(err error, usage string) { output = usage }, OptionsFirst: optionsFirst, SkipHelpFlags: !help, } args, err := p.ParseArgs(doc, argv, version) return args, output, err } var debugEnabled = false func debugOn(l ...interface{}) { debugEnabled = true debug(l...) } func debugOff(l ...interface{}) { debug(l...) debugEnabled = false } func debug(l ...interface{}) { if debugEnabled { fmt.Println(l...) } } ))entry(nameerror.gonode(typeregularcontents0package 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 ))entry(nameexample_test.gonode(typeregularcontents¢package docopt import ( "fmt" "sort" ) func ExampleParseArgs() { usage := `Usage: example tcp [...] [--force] [--timeout=] example serial [--baud=] [--timeout=] example --help | --version` // Parse the command line `example tcp 127.0.0.1 --force` argv := []string{"tcp", "127.0.0.1", "--force"} opts, _ := ParseArgs(usage, argv, "0.1.1rc") // Sort the keys of the options map var keys []string for k := range opts { keys = append(keys, k) } sort.Strings(keys) // Print the option keys and values for _, k := range keys { fmt.Printf("%9s %v\n", k, opts[k]) } // Output: // --baud // --force true // --help false // --timeout // --version false // [127.0.0.1] // // serial false // tcp true } func ExampleOpts_Bind() { usage := `Usage: example tcp [...] [--force] [--timeout=] example serial [--baud=] [--timeout=] example --help | --version` // Parse the command line `example serial 443 --baud=9600` argv := []string{"serial", "443", "--baud=9600"} opts, _ := ParseArgs(usage, argv, "0.1.1rc") var conf struct { Tcp bool Serial bool Host []string Port int Force bool Timeout int Baud int } opts.Bind(&conf) if conf.Serial { fmt.Printf("port: %d, baud: %d", conf.Port, conf.Baud) } // Output: // port: 443, baud: 9600 } ))entry(nameexamplesnode(type directoryentry(name argumentsnode(type directoryentry(name arguments.gonode(typeregularcontentsdpackage main import ( "fmt" "github.com/docopt/docopt-go" ) var usage = `Usage: arguments [-vqrh] [FILE] ... arguments (--left | --right) CORRECTION FILE Process FILE and optionally apply correction to either left-hand side or right-hand side. Arguments: FILE optional input file CORRECTION correction angle, needs FILE, --left or --right to be present Options: -h --help -v verbose mode -q quiet mode -r make report --left use left-hand side --right use right-hand side` func main() { arguments, _ := docopt.ParseDoc(usage) fmt.Println(arguments) } ))entry(namearguments_test.gonode(typeregularcontentspackage main import ( "github.com/docopt/docopt-go/examples" ) func Example() { examples.TestUsage(usage, "arguments -qv") examples.TestUsage(usage, "arguments --left file.A file.B") // Output: // --help false // --left false // --right false // -q true // -r false // -v true // CORRECTION // FILE [] // // --help false // --left true // --right false // -q false // -r false // -v false // CORRECTION file.A // FILE [file.B] } ))))entry(name calculatornode(type directoryentry(name calculator.gonode(typeregularcontentsäpackage main import ( "fmt" "github.com/docopt/docopt-go" ) var usage = `Not a serious example. Usage: calculator ( ( + | - | * | / ) )... calculator [( , )]... calculator (-h | --help) Examples: calculator 1 + 2 + 3 + 4 + 5 calculator 1 + 2 '*' 3 / 4 - 5 # note quotes around '*' calculator sum 10 , 20 , 30 , 40 Options: -h, --help ` func main() { arguments, _ := docopt.ParseDoc(usage) fmt.Println(arguments) } ))entry(namecalculator_test.gonode(typeregularcontents×package main import ( "github.com/docopt/docopt-go/examples" ) func Example() { examples.TestUsage(usage, "calculator 1 + 2 + 3 + 4 + 5") examples.TestUsage(usage, "calculator 1 + 2 * 3 / 4 - 5") examples.TestUsage(usage, "calculator sum 10 , 20 , 30 , 40") // Output: // * 0 // + 4 // , 0 // - 0 // --help false // / 0 // // [1 2 3 4 5] // // * 1 // + 1 // , 0 // - 1 // --help false // / 1 // // [1 2 3 4 5] // // * 0 // + 0 // , 3 // - 0 // --help false // / 0 // sum // [10 20 30 40] } ))))entry(name config_filenode(type directoryentry(nameconfig_file.gonode(typeregularcontentsæpackage main import ( "encoding/json" "fmt" "github.com/docopt/docopt-go" "strings" ) func loadJSONConfig() map[string]interface{} { var result map[string]interface{} jsonData := []byte(`{"--force": true, "--timeout": "10", "--baud": "9600"}`) json.Unmarshal(jsonData, &result) return result } func loadIniConfig() map[string]interface{} { iniData := ` [default-arguments] --force --baud=19200 =localhost` // trivial ini parser // default value for an item is bool: true (for --force) // otherwise the value is a string iniParsed := make(map[string]map[string]interface{}) var section string for _, line := range strings.Split(iniData, "\n") { if strings.HasPrefix(line, "[") { section = line iniParsed[section] = make(map[string]interface{}) } else if section != "" { kv := strings.SplitN(line, "=", 2) if len(kv) == 1 { iniParsed[section][kv[0]] = true } else if len(kv) == 2 { iniParsed[section][kv[0]] = kv[1] } } } return iniParsed["[default-arguments]"] } // merge combines two maps. // truthiness takes priority over falsiness // mapA takes priority over mapB func merge(mapA, mapB map[string]interface{}) map[string]interface{} { result := make(map[string]interface{}) for k, v := range mapA { result[k] = v } for k, v := range mapB { if _, ok := result[k]; !ok || result[k] == nil || result[k] == false { result[k] = v } } return result } func main() { usage := `Usage: config_file tcp [] [--force] [--timeout=] config_file serial [--baud=] [--timeout=] config_file -h | --help | --version` jsonConfig := loadJSONConfig() iniConfig := loadIniConfig() arguments, _ := docopt.ParseArgs(usage, nil, "0.1.1rc") // Arguments take priority over INI, INI takes priority over JSON result := merge(arguments, merge(iniConfig, jsonConfig)) fmt.Println("JSON config: ", jsonConfig) fmt.Println("INI config: ", iniConfig) fmt.Println("Result: ", result) } ))))entry(namecountednode(type directoryentry(name counted.gonode(typeregularcontents–package main import ( "fmt" "github.com/docopt/docopt-go" ) var usage = `Usage: counted --help counted -v... counted go [go] counted (--path=)... counted Try: counted -vvvvvvvvvv counted go go counted --path ./here --path ./there counted this.txt that.txt` func main() { arguments, _ := docopt.ParseDoc(usage) fmt.Println(arguments) } ))entry(namecounted_test.gonode(typeregularcontents¾package main import ( "github.com/docopt/docopt-go/examples" ) func Example() { examples.TestUsage(usage, "counted -vvvvvvvvvv") examples.TestUsage(usage, "counted go go") examples.TestUsage(usage, "counted --path ./here --path ./there") examples.TestUsage(usage, "counted this.txt that.txt") // Output: // --help false // --path [] // -v 10 // [] // go 0 // // --help false // --path [] // -v 0 // [] // go 2 // // --help false // --path [./here ./there] // -v 0 // [] // go 0 // // --help false // --path [] // -v 0 // [this.txt that.txt] // go 0 } ))))entry(name examples.gonode(typeregularcontentspackage examples import ( "fmt" "sort" "strings" "github.com/docopt/docopt-go" ) // TestUsage is a helper used to test the output from the examples in this folder. func TestUsage(usage, command string) { args, _ := docopt.ParseArgs(usage, strings.Split(command, " ")[1:], "") // Sort the keys of the arguments map var keys []string for k := range args { keys = append(keys, k) } sort.Strings(keys) // Print the argument keys and values for _, k := range keys { fmt.Printf("%9s %v\n", k, args[k]) } fmt.Println() } ))entry(namefake-gitnode(type directoryentry(namebranchnode(type directoryentry(name git_branch.gonode(typeregularcontents¦package main import ( "fmt" "github.com/docopt/docopt-go" ) func main() { usage := `usage: git branch [options] [-r | -a] [--merged= | --no-merged=] git branch [options] [-l] [-f] [] git branch [options] [-r] (-d | -D) git branch [options] (-m | -M) [] Generic options: -h, --help -v, --verbose show hash and subject, give twice for upstream branch -t, --track set up tracking mode (see git-pull(1)) --set-upstream change upstream info --color= use colored output -r act on remote-tracking branches --contains= print only branches that contain the commit --abbrev= use digits to display SHA-1s Specific git-branch actions: -a list both remote-tracking and local branches -d delete fully merged branch -D delete branch (even if not merged) -m move/rename a branch and its reflog -M move/rename a branch, even if target exists -l create the branch's reflog -f, --force force creation (when already exists) --no-merged= print only not merged branches --merged= print only merged branches ` args, _ := docopt.ParseDoc(usage) fmt.Println(args) } ))))entry(namecheckoutnode(type directoryentry(namegit_checkout.gonode(typeregularcontentsępackage main import ( "fmt" "github.com/docopt/docopt-go" ) func main() { usage := `usage: git checkout [options] git checkout [options] -- ... options: -q, --quiet suppress progress reporting -b create and checkout a new branch -B create/reset and checkout a branch -l create reflog for new branch -t, --track set upstream info for new branch --orphan new unparented branch -2, --ours checkout our version for unmerged files -3, --theirs checkout their version for unmerged files -f, --force force checkout (throw away local modifications) -m, --merge perform a 3-way merge with the new branch --conflict