Giter VIP home page Giter VIP logo

docopt.go's Introduction

docopt-go

Build Status Coverage Status GoDoc

An implementation of docopt in the Go programming language.

docopt helps you create beautiful command-line interfaces easily:

package main

import (
	"fmt"
	"github.com/docopt/docopt-go"
)

func main() {
	  usage := `Naval Fate.

Usage:
  naval_fate ship new <name>...
  naval_fate ship <name> move <x> <y> [--speed=<kn>]
  naval_fate ship shoot <x> <y>
  naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
  naval_fate -h | --help
  naval_fate --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
  --moored      Moored (anchored) mine.
  --drifting    Drifting mine.`

	  arguments, _ := docopt.ParseDoc(usage)
	  fmt.Println(arguments)
}

docopt parses command-line arguments based on a help message. Don't write parser code: a good help message already has all the necessary information in it.

Installation

⚠ Use the alias "docopt-go". To use docopt in your Go code:

import "github.com/docopt/docopt-go"

To install docopt in your $GOPATH:

$ 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:

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)

More documentation is available at godoc.org.

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.

Tests

All tests from the Python version are implemented and passing at Travis CI. New language-agnostic tests have been added to test_golang.docopt.

To run tests for docopt-go, use go test.

docopt.go's People

Contributors

aviddiviner avatar kbatten avatar mboersma avatar th0114nd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

docopt.go's Issues

List flags

I was recently surprised to discover that while arguments can be repeated, flags cannot. e.g. these are acceptable docstrings, but they don't behave as expected:

-v  verbose (specify multiple times for more verbose)
-x=<pattern>...  exclude files that match <pattern>

Neither of these cases seem to be addressed, although they're pretty common. The "verbose" case I kind of understand, since it'd take some kind of docstring magic to indicate to the parse what's meant. But the "exclude" seems to fall within the documentation as written for docopt, and instead returns a parsing error.

map[string]interface{} is cumbersome in Go

I know that in Python a dict works well. But in Go a map[string]interface{} is actually cumbersome as you have to cast the value to string or int. map[string]string would be better as it eliminates the casting, but still creates a lot of unnecessary Unmarshal work.

I would suggest that docopt.go work more like Go's encoding packages (which uses reflect). Essentially something like this:

type Options struct {
    Command string `docopt:"<command>"`
    Speed int `docopt:"--speed"`
    Duration time.Duration `docopt:"--duration"` // Use time.ParseDuration
    Custom CustomValue `docopt:"--custom"` // Uses type UnmarshalDocopt interface
    Map map[string]string `docopt:""` // Put the rest of the options here
    Other string // Ignore this because it doesn't have docopt: tag
}

var doc = `...` // Ussage/Options text here

func main() {
    p := docopt.NewParser(doc, true, "App 2.0", false)
    var opt Options // can also be a map[string]string
    if err := p.Parse(&opt); err != nil {
        log.Fatal(err)
    }
}

This package does something similar to the above example, but all the options are specified in tags, which get really ...really... long. With this you simply specify the name in a tag as you would in the map.

I would also consider it bad practice in Go to do an os.Exit inside of Parse/NewParser. The package user should have complete control over logging and exiting behavior inside their main. So I would suggest the above example look like this:

func main() {
    p := docopt.NewParser(doc, false) // Removed two middle options
    var opt Options
    if err := p.Parse(&opt); err != nil {
        log.Fatal(err)
    }
    if opt.Version { // Added Version bool `docopt:"--version"` to Options
        println("App 2.0")
        return
    }
    if opt.Help { // Added Help bool `docopt:"--help"` to Options
        println(doc) // OR p.PrintHelp()
        return
    }
}

Another neat idea (and perhaps this should be in another issue) would be to have the ability to fill values from an ini file like this:

type Options struct {
    Config string `docopt:"--config,ini"` // The "ini" flag tells docopt to read this string as a filename
    // ...
}

Parsing errors

Something not quite right here:

$ taskcluster-proxy -h
Usage: taskcluster-proxy [(-p|--port) <port>] [--client-id <clientId> --access-token <accessToken> [--certificate <certificate>]] ([-a|--all-scopes]|([-t|--task-id <taskId>] [-s|--scopes <scope>...]))
$ taskcluster-proxy -p 4 --access-token 43434

2018/03/01 19:44:01 {
  "--access-token": true,
  "--all-scopes": false,
  "--certificate": false,
  "--client-id": false,
  "--port": false,
  "--scopes": false,
  "--task-id": false,
  "-a": false,
  "-p": true,
  "-s": false,
  "-t": false,
  "\u003caccessToken\u003e": null,
  "\u003ccertificate\u003e": null,
  "\u003cclientId\u003e": "43434",
  "\u003cport\u003e": "4",
  "\u003cscope\u003e": [],
  "\u003ctaskId\u003e": null
}

As you see, the parsing should not succeed, since --access-token is specified without --client-id, yet the parsing succeeds, and assigns the access token to the <clientId> property.

invalid arg information not given, source of errors totally unclear

Consider the trivial usage:

Usage:
  naval_fate.py new <name>

and a command line of: naval_fate.py new foo bar

The resulting output simply shows usage, with identifying the source of the problem.

Usage:
  naval_fate.py new <name>

It seems not only reasonable, but required that some context for the error be given.

After looking into the code, it is clear that it's available, but not bubbled up. PR coming shortly.

Can not specify a flags 2+ times

Hello, I have this docopt help-usage:

package main

import (
    "fmt"

    "github.com/docopt/docopt-go"
)

const (
    usage = `
Tool 1.0

Usage:
    tool [options] -P (-a|-r) <package>
    tool [options] -S (-a|-r) <config>

Options:
    -P --package     Package mode
        -a --add     add package
        -r --remove  remove package
    -S --service     Service mode
        -a --add     add service
        -r --remove  remove service
`
)

func main() {
    args, err := docopt.Parse(usage, nil, true, "tool 1.0", true, false)
    if err != nil {
        panic(err)
    }
    fmt.Printf("XXXXXX a.go:32: args: %#v\n", blah)
}

But when I run docopt.Parse with this usage, I got:

panic: -a is specified ambiguously 2 times

goroutine 1 [running]:
main.main()
        /home/vxw/a.go:30 +0x10a

So, this is really correct behaviour? Why usage can't have a repetable flags?

Enable option to disable/enable check for non-zero values during Bind

It would be great if it was possible to disable the non-zero check during a bind, so that we can pre-populate certain values and allow for DocOpt to over-ride when necessary.

My use case is i'm using another library to first parse environment variables, and would like program arguments to over-ride when necessary.

Maybe this logic would break other things, so if there's a better suggestion to combine Environment variables with DocOpt i'd love to hear them!

-vvv looks broken

Hi. After the merge of the big rewrite about a week ago it seems that [-vvv] handling is broken.
Before, something along

Options:
  mybin [-vvv] act

With args[“-v”].(int) would take values from 0 to 3 for the inputs:

  • mybin act
  • mybin -v act
  • mybin -vv act
  • mybin -vvv act

Now with the new parser and the new API args.Int(“-v”) gives a value of 0 and an error along the lines of “this is uncastable” for any amount of Vs.

I will work on creating a minimal example that uses both APIs tomorrow. I don’t remember that I found this usage in the golang examples/tests.

But then I am maybe just misusing the newer api. What do you think?
cc @aviddiviner

Ellipsis not working for anything but strings

Suppose I have this program:

package main

import (
	`fmt`
	`github.com/docopt/docopt-go`
)

func main() {
	opts, _ := docopt.ParseDoc(`
		Usage:
		    mytool --number=<num>...`)

	var conf struct {
		Number []int
	}
	if err := opts.Bind(&conf); err != nil {
		panic(err)
	}

	fmt.Printf("%v\n", conf)
}

When executing go run mytool.go I get this error:

panic: value of "--number" is not assignable to "Number" field

goroutine 1 [running]:
main.main()
        /<path_to_script>/mytool.go:17 +0x190
exit status 2

If I change []int to []string everything works.

Issue with short arg parsing using optional space

The docent standard supports an optional space after short args like -c 50 and should be parsed into a "-c": "50" but it currently is parsed into "-c": " 50" which has the side effect of not being able to be coerced into a int type because of the space

From docent.org

Short options can have arguments specified after optional space:
-f FILE is equivalent to -fFILE.

When a line follows `Options:` declaration, options don't parse correctly

Description

When a non-option line comes after the Options: declaration, parsing fails in weird ways. Not only are options missing, but -h and --help are now split. This doesn't happen at try.docopt.org.

Repro

  1. Start with the options shortcut example
package main

import (
	"fmt"
	"github.com/docopt/docopt-go"
)

func main() {
	usage := `Example of program which uses [options] shortcut in pattern.

Usage:
  options_shortcut_example [options] <port>
  options_shortcut_example -h | --help

Options:
  -h --help                show this help message and exit
  --version                show version and exit
  -n, --number N           use N as a number
  -t, --timeout TIMEOUT    set timeout TIMEOUT seconds
  --apply                  apply changes to database
  -q                       operate in quiet mode`

	arguments, _ := docopt.Parse(usage, nil, false, "1.0.0rc2", false)
	fmt.Println(arguments)
}
  1. Modify as such
 Options:
+These are things
   -h --help                show this help message and exit

Expected Behavior

$ go run options_shortcut_example.go --help
map[<port>:<nil> --help:true --version:false --number:<nil> --timeout:<nil> --apply:false -q:false]

Actual Behavior

$ go run options_shortcut_example.go --help
map[<port>:<nil> -h:false --help:true]

allow newline after Usage / Options

it just outputs the help, no error or anything, kinda confusing, having them squished looks weird but that whitespace should be optional and left up to the author anyway. Same with leading/trailing whitespace, I'm not a fan of stdio that is shoved against the terminal edges so a tool forcing me to do that is a little meh

Unknown command locally, but works in try docopt

I have the following docopt spec:

poisson

	Usage:
		poisson
		poisson start --project=<project> [--norestore]
		poisson populatebq --project=<project>
		poisson populatemongo --project=<project>

	Options:
		-h --help			Show this screen.
		--version			Show version.
		--project=<project>	Project id.
		--norestore			If specified restore of db will not take place.

Note that this is the first time using docopt, so I could probably do something differently. With that said. When I try to run the app that has this specification with the following line:

go run main.go start --norestore --project=projectname

It fails with unknown command. If I remove the last line --norestore... from the spec if works fine. The first one also works on try docopt: http://try.docopt.org/?doc=poisson%0D%0A%0D%0A%09Usage%3A%0D%0A%09%09poisson%0D%0A%09%09poisson+start+--project%3D%3Cproject%3E+%5B--norestore%5D%0D%0A%09%09poisson+populatebq+--project%3D%3Cproject%3E%0D%0A%09%09poisson+populatemongo+--project%3D%3Cproject%3E%0D%0A%0D%0A%09Options%3A%0D%0A%09%09-h+--help%09%09%09Show+this+screen.%0D%0A%09%09--version%09%09%09Show+version.%0D%0A%09%09--project%3D%3Cproject%3E%09Project+id.%0D%0A%09%09--norestore%09%09%09If+specified+restore+of+db+will+not+take+place.&argv=start+--project%3Dasd+--norestore

Pre-built binaries

Could you please provide binaries for ARM? (in particular, Android and Raspberry Pi, if possible)
Thanks!

Super old release tags

Was reading README.md on github.com and tried using it with dep ensure, but found out that the "latest" release tag is 0.6.2 (from 2016).

Quick fix for me was to add branch constraint in Gopkg.toml, but it would be nice having a more up-to-date release tag.

Wrong optional keyword match

It seems if a command-like argument (like a keyword) is use in an optional block, it matches the wrong thing.
In the following repro, "cmd" is matched with "opt1" if "keyword" is not specified. If it is specified it works fine.
Note that if instead of a keyword, an option (like "--option") is specified it works fine.

package main

import (
	"fmt"
	"github.com/docopt/docopt-go"
)

func main() {
	usage := `To match optional with keyword.

Usage:
  keyword-match: [keyword <opt1>] [<args>...]
`
	args, err := docopt.ParseArgs(usage, []string{"cmd"}, "")
	fmt.Printf("%#v\n", args) // BUG prints: docopt.Opts{"<opt1>":"cmd", "keyword":false}
	fmt.Printf("%#v\n", err)  // prints: <nil>

	args, err = docopt.ParseArgs(usage, []string{"keyword", "opt1", "cmd"}, "")
	fmt.Printf("%#v\n", args) // prints: docopt.Opts{"<args>":[]string{"cmd"}, "<opt1>":"opt1", "keyword":true}
	fmt.Printf("%#v\n", err)  // prints: <nil>

	usage = `To match optional with option.

Usage:
  keyword-match: [--option=<opt1>] [<args>...]
`
	args, err = docopt.ParseArgs(usage, []string{"cmd"}, "")
	fmt.Printf("%#v\n", args) // prints: docopt.Opts{"--option":interface {}(nil), "<args>":[]string{"cmd"}}
	fmt.Printf("%#v\n", err)  // prints: <nil>

	args, err = docopt.ParseArgs(usage, []string{"--option", "opt1", "cmd"}, "")
	fmt.Printf("%#v\n", args) // prints: docopt.Opts{"--option":"opt1", "<args>":[]string{"cmd"}}
	fmt.Printf("%#v\n", err)  // prints: <nil>
}

boolean options don't seem to work

Boolean options don't seem to work the way they should. Here is an example:

package main

import (
	"fmt"
	"github.com/docopt/docopt-go"
)

var usage string = `
Mytest.

Usage:
	mytest [options]

Options:
  --flag	a flag
`

func main() {
	opts, _ := docopt.ParseDoc(usage)
	flag, err := opts.Bool("--flag")
	fmt.Println(flag)
	fmt.Println(err)
}
$ go run mytest.go
false
key: "--flag" failed type conversion
$ go run mytest.go --flag
--flag requires argument
Usage:
	mytest [options]
exit status 1
$ go run mytest.go --flag=true
false
key: "--flag" failed type conversion
$ go version
go version go1.14.1 linux/amd64
$ 

Mixing up paramethers

with my current config

usage := `buggy example

Usage:
  test -d (<from> <to>)
  test -d (<from> <to>) [--site <site>]
  test -d (<from> <to>)[--geocountry <geocountry>]
  test -d (<from> <to>)[--site <site>] [--geocountry <geocountry>]


Options:
  -h --help     Show this screen.
  -d --date     Dates of report.
  -s --site     Site id of report.
  -g --geocountry  Country code of site to load from geo-ip database.`

I execute it with params -d 123 456 -g DE -s 1 and got result like

{
  "--date": true, 
  "--geocountry": true, 
  "--site": true, 
  "<from>": "123", 
  "<geocountry>": "1", 
  "<site>": "DE", 
  "<to>": "456"
}

As you could see the parameters are mixed up. The question is it expected behavior or just a bug?

Playground based on try.docopt.org
http://try.docopt.org/?doc=buggy+example%0D%0A%0D%0AUsage%3A%0D%0A++test+-d+%28%3Cfrom%3E+%3Cto%3E%29%0D%0A++test+-d+%28%3Cfrom%3E+%3Cto%3E%29+%5B--site+%3Csite%3E%5D%0D%0A++test+-d+%28%3Cfrom%3E+%3Cto%3E%29%5B--geocountry+%3Cgeocountry%3E%5D%0D%0A++test+-d+%28%3Cfrom%3E+%3Cto%3E%29%5B--site+%3Csite%3E%5D+%5B--geocountry+%3Cgeocountry%3E%5D%0D%0A%0D%0A%0D%0AOptions%3A%0D%0A++-h+--help+++++Show+this+screen.%0D%0A++-d+--date+++++Dates+of+report.%0D%0A++-s+--site+++++Site+id+of+report.%0D%0A++-g+--geocountry++Country+code+of+site+to+load+from+geo-ip+database.%0D%0A%0D%0A&argv=-d+123+456+-g+DE+-s+1

Show example of repeatable flag

Does docopt support repeating flags, like hello -e name:bob -e hair:nil? If so, could the README please add an example of the docopt string syntax for enabling this for one or more named flags?

Unwanted os.Exit()

Hi,

I've just started a command line application that will act as an alternative for the 'man' command. One of the planned options is [--explain ]. For example,

gman --explain "rsync -avF src dest"

In the example above, I would like to use docopt to parse the rsync options. The problem is that docopt.Parse() may call os.Exit(). For this and other use cases, that is less than ideal. It would be nice to have a Parse method that did not call os.Exit(). Something like this would be great:

func ParseContinue(doc string, argv []string, help bool, version string, optionsFirst bool) (map[string]interface{}, string, error) {
    args, output, err := parse(doc, argv, help, version, optionsFirst)
    return args, output, err
}

If I need to, of course, I can fork and add the method for my purpose, but I at least wanted to make you aware of the use case.

FWIW, calling os.Exit() also prevents the call of any defer methods. I doubt that many people will call defer before parsing command line options, but it's another possible argument for such a method.

Thanks.

Ellipsis not documented

When greping through the repository I couldn't find a single occurrence of the word 'ellipsis'.

On the GoDoc page I found one example where Bind() is used to bind to a struct containing Host []string.

I didn't find any good way to get ellipsis options without binding to a struct. In
examples/fake-git/fakegit.go I found this line cmdArgs := args["<args>"].([]string), but any casting error can't be caught here. Is there a better way?

In my opinion all this should be documented. If you can tell me about any functionality I missed, I'd be happy to write a paragraph for the GoDoc documentation and create a pull request.

field could not be overwrite

when opts bind to struct, if field has default value, it could not be overwrite, but in most cases, setting default value is better I think.

Not returning ints

The documentation says "interface{} can be bool, int, string, []string.", implying (I guess?) that numeric arguments ought to be be an int in the arguments map. However, for options such as

  --scan-intv <s>  Repository scan interval, in seconds [default: 60]

the "60" is returned as a string-typed interface{}.

Recursive build and test fails

In a project which has docopt-go as a dependency, the examples directory in the root of the repository prevents building with go build ./... from working.

Running tests with go test ./... also fails. The reason it fails is that main is redeclared multiple times in the example files.

Building a project with go build ./... and testing with go test ./... seems to be the convention for many Go projects, and it's the default used by Travis CI.

--key=VAL parsing broken in example

This should succeed at parsing and print its args, but fails instead:

$ go run examples/options/options_example.go --ignore=E,W6
Usage:
  options_example [-hvqrf NAME] [--exclude=PATTERNS]
                     [--select=ERRORS | --ignore=ERRORS] [--show-source]
                     [--statistics] [--count] [--benchmark] PATH...
  options_example (--doctest | --testsuite=DIR)
  options_example --version
exit status 1

It appears argument parsing of the format --key=VAL is broken generally in docopt-go.

Whitespace is killing me

For anyone interested in using docopt in Go, this seems like a great option. However, in it's current state, this package is harder to work with than the speed gains potentially provided by DocOpt. I am a firm believer in docopt and what it tries to do, so understand I really want this package to work, sadly it does not.

This issue is meant to steer people away until major issues are fixed.

The critical issues can be found by perusing the issues here in this repo, so I won't rehash them, but suffice to say i've wasted more hours debugging the parsing this package uses, then actually using it.

Git subcommands example uses Go binary

Is there a way to properly implement subcommands without using the Go binary to actually run them? The use case is building + shipping + deploying a binary to boxes that do not have Go installed on them.

Array values duplicated with OneOrMore options (...)

The following usage

Usage:
  %[1]s [-u <URL>...] (-D <DOMAINFILE> [-V <VOLUMEFILE> -p <STORAGEPOOL> --start])
  %[1]s [-u <URL>...] (-V <VOLUMEFILE> [-p <STORAGEPOOL>])
  %[1]s [-u <URL>...] (--domdata <DOMAINDATA> [--voldata <VOLUMEDATA> -p <STORAGEPOOL>] --start)
  %[1]s [-u <URL>...] (--voldata <VOLUMEDATA> [-p <STORAGEPOOL>])
  %[1]s [-u <URL>...] (-R <DOMAINNAME>)

Options:
  -u, --url <URL>            server url [default: qemu:///system]
*******

with cli opts -u qemu+ssh://user@hostname/system -u test
produces array with duplicated 2-nd value: [qemu+ssh://user@hostname/system test test test test test]

ParseArgs fails to compile [--speed=<kn>]

On commit ee0de3b

package main

import (
	"fmt"
	"os"
	"github.com/docopt/docopt-go"
)

func main() {
	usage := `Naval Fate.

Usage:
  naval_fate.py ship [--speed=<kn>]
  naval_fate.py -h | --help
  naval_fate.py --version

Options:
  -h --help     Show this screen.
  --version     Show version.
  --speed=<kn>  Speed in knots [default: 10].
`

	{
		// this works
		args, err := docopt.ParseDoc(usage)
		if err != nil { panic(err) }
		fmt.Printf("%+v\n", args)
		fmt.Println(args["--speed"])
	}

	{
		// this panics
		parser := &docopt.Parser{
			HelpHandler:  docopt.PrintHelpOnly,
			OptionsFirst: true,
		}
		args, err := parser.ParseArgs(usage, os.Args[1:], "naval_fate.py")
		if err != nil { panic(err) }
		fmt.Printf("%+v\n", args)
		fmt.Println(args["--speed"])
	}
}
∀ go run docopt_wat.go ship --speed 23
map[ship:true --speed:23 --help:false --version:false]
23
Usage:
  naval_fate.py ship [--speed=<kn>]
  naval_fate.py -h | --help
  naval_fate.py --version
panic: 

goroutine 1 [running]:
main.main()
	/home/pete/docopt_wat.go:36 +0x2f6
exit status 2

Bug: Help: false with `--help` does not return options when there are required arguments

Description

setting help: false, and providing --help, and having a required position argument at the command line causes docopt to not return any options/args and also print usage (without options)

Repro Steps

This is taken directly from the options_shortcut_example.

package main

import (
	"fmt"
	"github.com/docopt/docopt-go"
)

func main() {
	usage := `Example of program which uses [options] shortcut in pattern.

Usage:
  options_shortcut_example [options] <port>

Options:
  -h --help                show this help message and exit
  --version                show version and exit
  -n, --number N           use N as a number
  -t, --timeout TIMEOUT    set timeout TIMEOUT seconds
  --apply                  apply changes to database
  -q                       operate in quiet mode`

	fmt.Println("*** About To Parse ****")
	arguments, _ := docopt.Parse(usage, nil, false, "1.0.0rc2", false)
	fmt.Println("*** Done Parsing ****")
	fmt.Println(arguments)
}

Expected Output

( with exit: false and help: false )

$ go run options_shortcut_example.go --help
*** About To Parse ****
*** Done Parsing ****
map[--number:<nil> --timeout:<nil> --apply:false -q:false <port>:<nil> --help:true --version:false]

From reading the docs, I expect to get options back from the parser when --help is on the commandline and help: false parse option is used. The whole idea of help: false is so I can print a custom message, or perform other work.

Actual Output

$ go run options_shortcut_example.go --help
*** About To Parse ****
Usage:
  options_shortcut_example [options] <port>
exit status 1

$ go run options_shortcut_example.go
*** About To Parse ****
Usage:
  options_shortcut_example [options] <port>
exit status 1

When exit is set to false, you can also see there are no options:

$ go run options_shortcut_example.go --help
*** About To Parse ****
Usage:
  options_shortcut_example [options] <port>
*** Done Parsing ****
map[]

This is most likely because the <port> positional argument is required, and because it wasn't provided. But that means that --help is no longer special.

Workaround

Usage:
   options_shortcut_example [-h|--help]|([options] <port>)

This seems to work, as it indicates you can either get help, or run the actual command. But this is super hacky, and defeats the elegance of this framework. It also means --help is no longer special.

Parse docopt even if no args are passed

Hi. I am looking for a future to parse docopt even if no args were given for parser.

Real use-case - I want to get all flags (by flag I mean all options a command can receive) and use them in autocomplete.

Basically I need only keys from opts map[string]interface{} map of flags. I then filter them as I need.

Example:

doc = `Usage: somecli run [--debug] [--config=<config>] <app>
Options:
  --debug                   Run app with debug
  --config=<config>         Run with a config file
  <app>                     An app to run
`
onlyFlage := true
opts, err := docopt.ParseDoc(doc, onlyFlags)

The values of flags doesn't matter in this case and can be default values (bool, empty string, nil, etc)

I am ready to implement this feature if you are okay with an idea.
Thanks!

Versioning of library

I want to prepare a package for Fedora and have a question - how versions will go? Do you want to follow python development and use the same versions or just to code without regular releases? Both answers are right (it's for nice implementation only) :) I can see 0.6.1 tag which is one year old and I'm not sure how it will continue.

would like support for "cmd <source>... <destination>"

I have a cp-like command that takes multiple sources and a single destination. I'm trying to replicate that with docopt, but it consumes all of the input args for the ... match and then fails to match . The parser either needs a way to put back input tokens and try again (back tracking) or it needs to consider the next token (look ahead).

I tool a look at the source, for match(). I couldn't see any way to make this change. If you have any suggestions, I would be happy to work on a patch.

[enhancement] add an error message when launching without mandatory argument

reported in docopts (shell wrapper) docopt/docopts#17

I made a go example to reproduce the behavior:

https://github.com/Sylvain303/docopts/blob/debug-issues/issues/17-Empty-error-without-mandatory-argument/atest.go

$ go run atest.go
my error: 
Usage: atest.sh <arg>
       atest.sh ( -h | --help )
       atest.sh ( -V | --version )
exit status 1

Would it be possible to have help full error in err when receiving it in error Handler:

https://github.com/Sylvain303/docopts/blob/debug-issues/issues/17-Empty-error-without-mandatory-argument/atest.go#L41

Strange error when parsing usage: unmatched '(', expected: ')' got: ''

package main

import (
    "fmt"
    "os"
    docopt "github.com/docopt/docopt-go"
)

func main() {
    usage := `cprint

Enhance terminal output without typing ANSI escape patterns

Usage:
  cprint [--attr=<attr>] --color=<color> <word>...
  cprint --showattrs
  cprint --showcolors

Options:
  --attr=<attr>     Attribute
  --color=<color>      Desired color
  --showattrs       Show attributes
  --showcolors          Show colors`

    args, err := docopt.Parse(usage, nil, true, "0.1", false)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    fmt.Println(args)
}

Print statements would indicate that somewhere along the way a parseSeq call attempts to call parseAtom and it fails because the ([ and )] characters are unbalanced in the tokenList. There is an extra ).

If I add a ) char after --showcolors the error goes away.

Bind() does not work if usage have "--" separator

If command is declared with usage like this:

command --flag -- <args>...

Bind() invokation will fail with following error:

mapping of "--" is not found in given struct, or is an unexported field

I guess -- should be filtered out when binding args.

cc @aviddiviner

`go get github.com/docopt/docopt.go` fails because of repo's name

go get fails because of the .go extension, as it expects the package path to be a directory: stat github.com/docopt/docopt.go: no such file or directory

Plus, this is smell and a bad practice in Go packaging. Please, rename it to docopt-go, go-docopt or similar.

Version tag is out of date.

With the upcoming move to go modules access to new features will be inaccessible. Can there be tags for the current stable version?

Default values not being set

Doc:

`Paxos.

Usage:
  paxos <address> <address> <address>... [--chatty=<level>] [--latency=<milliseconds>]
  paxos -h | --help
  paxos --version

Options:
  <port>        Port on which to receive connections [default: 3410].
  -c --chatty   Logging level higher value displays more logs gives the [default: 0].
  -l --latency  Latency inserted between messages duration is randomized between n and 2n [default: 1000].
  -h --help     Show this screen.`

Default value for latency is always set to go's default value of 0

Saner indentation handling

Normally, the docopt spec would have usage strings indenting with two spaces. However, Go formatting overall prefers a hard tab, which often conflicts with styling tools like gofmt.

When the usage string (e.g., a Go multiline backticked string) has a mix of hard and soft tabs, docopt prints a misaligned help message. While this is a cosmetic error, this conflict risks causing parse errors.

For docopt-go, could we expand the parser to treat \t as equivalent to two spaces?

question: would you be interested in a code review of the Go implementation?

Hi there,

I like the concept of documenting CLI tools the same way we do for REST APIs, but I am also a Go expert with opinions on the subject and feel like the API for the library is far from idiomatic.

I could send a bunch of PRs / issues or I could also do a video review (plus a big PR at the end) as I've previously done for my YouTube series justforfunc.

Would you be interested on any of those? Is the API fixed or do you still accept non backwards compatible improvements?

Cheers,
Francesc

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.