diff --git a/go.mod b/go.mod index 5d5ed0c..1b884b1 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/BurntSushi/toml v0.3.1 - github.com/akamensky/argparse v1.2.2 + github.com/akamensky/argparse v1.4.0 github.com/beevik/etree v1.1.0 github.com/karrick/godirwalk v1.16.1 github.com/mattn/go-sqlite3 v1.14.2 diff --git a/go.sum b/go.sum index 70b88b7..a55c8f2 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= -github.com/akamensky/argparse v1.2.2 h1:P17T0ZjlUNJuWTPPJ2A5dM1wxarHgHqfYH+AZTo2xQA= -github.com/akamensky/argparse v1.2.2/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= +github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc= +github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= @@ -14,8 +14,10 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-sqlite3 v1.14.2 h1:A2EQLwjYf/hfYaM20FVjs1UewCTTFR7RmjEHkLjldIA= github.com/mattn/go-sqlite3 v1.14.2/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= @@ -34,13 +36,13 @@ go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -59,9 +61,11 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/djherbis/times.v1 v1.2.0 h1:UCvDKl1L/fmBygl2Y7hubXCnY7t4Yj46ZrBFNUipFbM= gopkg.in/djherbis/times.v1 v1.2.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= @@ -69,6 +73,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 h1:AQkaJpH+/FmqRjmXZPELom5zIERYZfwTjnHpfoVMQEc= howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= diff --git a/vendor/github.com/akamensky/argparse/.travis.yml b/vendor/github.com/akamensky/argparse/.travis.yml index ff0fcf7..8436a98 100644 --- a/vendor/github.com/akamensky/argparse/.travis.yml +++ b/vendor/github.com/akamensky/argparse/.travis.yml @@ -3,7 +3,7 @@ sudo: false go: - "1.x" before_install: - - go get github.com/mattn/goveralls + - go install github.com/mattn/goveralls@latest script: - go test -v . - $GOPATH/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/akamensky/argparse/README.md b/vendor/github.com/akamensky/argparse/README.md index 9b7c3e7..db72f70 100644 --- a/vendor/github.com/akamensky/argparse/README.md +++ b/vendor/github.com/akamensky/argparse/README.md @@ -1,6 +1,6 @@ # Golang argparse -[![GoDoc](https://godoc.org/github.com/akamensky/argparse?status.svg)](https://godoc.org/github.com/akamensky/argparse) [![Go Report Card](https://goreportcard.com/badge/github.com/akamensky/argparse)](https://goreportcard.com/report/github.com/akamensky/argparse) [![Coverage Status](https://coveralls.io/repos/github/akamensky/argparse/badge.svg?branch=master)](https://coveralls.io/github/akamensky/argparse?branch=master) [![Build Status](https://travis-ci.org/akamensky/argparse.svg?branch=master)](https://travis-ci.org/akamensky/argparse) +[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/akamensky) [![GoDoc](https://godoc.org/github.com/akamensky/argparse?status.svg)](https://godoc.org/github.com/akamensky/argparse) [![Go Report Card](https://goreportcard.com/badge/github.com/akamensky/argparse)](https://goreportcard.com/report/github.com/akamensky/argparse) [![Coverage Status](https://coveralls.io/repos/github/akamensky/argparse/badge.svg?branch=master)](https://coveralls.io/github/akamensky/argparse?branch=master) [![Build Status](https://travis-ci.org/akamensky/argparse.svg?branch=master)](https://travis-ci.org/akamensky/argparse) Let's be honest -- Go's standard command line arguments parser `flag` terribly sucks. It cannot come anywhere close to the Python's `argparse` module. This is why this project exists. @@ -66,6 +66,17 @@ String will allow you to get a string from arguments, such as `$ progname --stri var myString *string = parser.String("s", "string", ...) ``` +Positional arguments can be used like this `$ progname value1`. +See [Basic Option Structure](#basic-option-structure) and [Positionals](#positionals). +```go +var myString *string = parser.StringPositional(nil) +var myString *string = parser.FilePositional(nil) +var myString *string = parser.FloatPositional(nil) +var myString *string = parser.IntPositional(nil) +var myString *string = parser.SelectorPositional([]string{"a", "b"}, nil) +var myString1 *string = parser.StringPositional(Options{Default: "beep"}) +``` + Selector works same as a string, except that it will only allow specific values. For example like this `$ progname --debug-level WARN` ```go @@ -134,9 +145,20 @@ var myLogFiles *[]os.File = parser.FileList("l", "log-file", os.O_RDWR, 0600, .. ``` You can implement sub-commands in your CLI using `parser.NewCommand()` or go even deeper with `command.NewCommand()`. +Addition of a sub-command implies that a subcommand is required. +Sub-commands are always parsed before arguments. +If a command has `Positional` arguments and sub-commands then sub-commands take precedence. Since parser inherits from command, every command supports exactly same options as parser itself, thus allowing to add arguments specific to that command or more global arguments added on parser itself! +You can also dynamically retrieve argument values and if they were parsed: +``` +var myInteger *int = parser.Int("i", "integer", ...) +parser.Parse() +fmt.Printf("%d", *parser.GetArgs()[0].GetResult().(*int)) +fmt.Printf("%v", *parser.GetArgs()[0].GetParsed()) +``` + #### Basic Option Structure The `Option` structure is declared at `argparse.go`: @@ -149,7 +171,7 @@ type Options struct { } ``` -You can Set `Required` to let it know if it should ask for arguments. +You can set `Required` to let it know if it should ask for arguments. Or you can set `Validate` as a lambda function to make it know while value is valid. Or you can set `Help` for your beautiful help document. Or you can set `Default` will set the default value if user does not provide a value. @@ -158,7 +180,7 @@ Example: ``` dirpath := parser.String("d", "dirpath", &argparse.Options{ - Require: false, + Required: false, Help: "the input files' folder path", Default: "input", }) @@ -176,6 +198,15 @@ There are a few caveats (or more like design choices) to know about: * `parser.Parse()` returns error in case of something going wrong, but it is not expected to cover ALL cases * Any arguments that left un-parsed will be regarded as error +##### Positionals +* `Positional` args have a set of effects and conditions: + * Always parsed after subcommands and non-positional args + * Always set Required=False + * Default is only used if the command or subcommand owning the arg `Happened` + * Parsed in Command root->leaf left->right order (breadth-first) + * Top level cmd consumes as many positionals as it can, from left to right + * Then in a descendeding loop for any command which `Happened` it repeats + * Positionals which are not satisfied (due to lack of input args) are not errors #### Contributing diff --git a/vendor/github.com/akamensky/argparse/argparse.go b/vendor/github.com/akamensky/argparse/argparse.go index efaf9d5..cb2cf28 100644 --- a/vendor/github.com/akamensky/argparse/argparse.go +++ b/vendor/github.com/akamensky/argparse/argparse.go @@ -11,6 +11,11 @@ import ( // DisableDescription can be assigned as a command or arguments description to hide it from the Usage output const DisableDescription = "DISABLEDDESCRIPTIONWILLNOTSHOWUP" +// Positional Prefix +// This must not overlap with any other arguments given or library +// will panic. +const positionalArgName = "_positionalArg_%s_%d" + //disable help can be invoked from the parse and then needs to be propogated to subcommands var disableHelp = false @@ -80,6 +85,14 @@ type Parser struct { // Options are specific options for every argument. They can be provided if necessary. // Possible fields are: // +// Options.positional - tells Parser that the argument is positional (implies Required). Set to true by using *Positional functions. +// Positional arguments must not have arg name preceding them and must come in a specific order. +// Positionals are parsed breadth-first (left->right from Command tree root to leaf) +// Positional sets Shortname="", ignores Required +// Positionals which are not satisfied will be nil but no error will be thrown +// Defaults are only set for unparsed positionals on commands which happened +// Use arg.GetParsed() to detect if arg was satisfied or not +// // Options.Required - tells Parser that this argument is required to be provided. // useful when specific Command requires some data provided. // @@ -99,6 +112,9 @@ type Options struct { Validate func(args []string) error Help string Default interface{} + + // Private modifiers + positional bool } // NewParser creates new Parser object that will allow to add arguments for parsing @@ -191,12 +207,13 @@ func (o *Command) Flag(short string, long string, opts *Options) *bool { var result bool a := &arg{ - result: &result, - sname: short, - lname: long, - size: 1, - opts: opts, - unique: true, + result: &result, + sname: short, + lname: long, + size: 1, + opts: opts, + unique: true, + argType: Flag, } if err := o.addArg(a); err != nil { @@ -217,12 +234,13 @@ func (o *Command) FlagCounter(short string, long string, opts *Options) *int { var result int a := &arg{ - result: &result, - sname: short, - lname: long, - size: 1, - opts: opts, - unique: false, + result: &result, + sname: short, + lname: long, + size: 1, + opts: opts, + unique: false, + argType: FlagCounter, } if err := o.addArg(a); err != nil { @@ -239,12 +257,13 @@ func (o *Command) String(short string, long string, opts *Options) *string { var result string a := &arg{ - result: &result, - sname: short, - lname: long, - size: 2, - opts: opts, - unique: true, + result: &result, + sname: short, + lname: long, + size: 2, + opts: opts, + unique: true, + argType: String, } if err := o.addArg(a); err != nil { @@ -254,6 +273,18 @@ func (o *Command) String(short string, long string, opts *Options) *string { return &result } +// See func String documentation +func (o *Command) StringPositional(opts *Options) *string { + if opts == nil { + opts = &Options{} + } + opts.positional = true + + // We supply a long name for documentation and internal logic + name := fmt.Sprintf(positionalArgName, o.name, len(o.args)) + return o.String("", name, opts) +} + // Int creates new int argument, which will attempt to parse following argument as int. // Takes as arguments short name (must be single character or an empty string) // long name and (optional) options. @@ -262,12 +293,13 @@ func (o *Command) Int(short string, long string, opts *Options) *int { var result int a := &arg{ - result: &result, - sname: short, - lname: long, - size: 2, - opts: opts, - unique: true, + result: &result, + sname: short, + lname: long, + size: 2, + opts: opts, + unique: true, + argType: Int, } if err := o.addArg(a); err != nil { @@ -277,6 +309,18 @@ func (o *Command) Int(short string, long string, opts *Options) *int { return &result } +// See func Int documentation +func (o *Command) IntPositional(opts *Options) *int { + if opts == nil { + opts = &Options{} + } + opts.positional = true + + // We supply a long name for documentation and internal logic + name := fmt.Sprintf(positionalArgName, o.name, len(o.args)) + return o.Int("", name, opts) +} + // Float creates new float argument, which will attempt to parse following argument as float64. // Takes as arguments short name (must be single character or an empty string) // long name and (optional) options. @@ -285,12 +329,13 @@ func (o *Command) Float(short string, long string, opts *Options) *float64 { var result float64 a := &arg{ - result: &result, - sname: short, - lname: long, - size: 2, - opts: opts, - unique: true, + result: &result, + sname: short, + lname: long, + size: 2, + opts: opts, + unique: true, + argType: Float, } if err := o.addArg(a); err != nil { @@ -300,6 +345,18 @@ func (o *Command) Float(short string, long string, opts *Options) *float64 { return &result } +// See func Float documentation +func (o *Command) FloatPositional(opts *Options) *float64 { + if opts == nil { + opts = &Options{} + } + opts.positional = true + + // We supply a long name for documentation and internal logic + name := fmt.Sprintf(positionalArgName, o.name, len(o.args)) + return o.Float("", name, opts) +} + // File creates new file argument, which is when provided will check if file exists or attempt to create it // depending on provided flags (same as for os.OpenFile). // It takes same as all other arguments short and long names, additionally it takes flags that specify @@ -319,6 +376,7 @@ func (o *Command) File(short string, long string, flag int, perm os.FileMode, op unique: true, fileFlag: flag, filePerm: perm, + argType: File, } if err := o.addArg(a); err != nil { @@ -328,9 +386,22 @@ func (o *Command) File(short string, long string, flag int, perm os.FileMode, op return &result } +// See func File documentation +func (o *Command) FilePositional(flag int, perm os.FileMode, opts *Options) *os.File { + if opts == nil { + opts = &Options{} + } + opts.positional = true + + // We supply a long name for documentation and internal logic + name := fmt.Sprintf(positionalArgName, o.name, len(o.args)) + return o.File("", name, flag, perm, opts) +} + // List creates new list argument. This is the argument that is allowed to be present multiple times on CLI. -// All appearances of this argument on CLI will be collected into the list of default type values ​​which is strings. If no argument -// provided, then the list is empty. Takes same parameters as String +// All appearances of this argument on CLI will be collected into the list of default type values which is strings. +// If no argument provided, then the list is empty. +// Takes same parameters as String. // Returns a pointer the list of strings. func (o *Command) List(short string, long string, opts *Options) *[]string { return o.StringList(short, long, opts) @@ -344,12 +415,13 @@ func (o *Command) StringList(short string, long string, opts *Options) *[]string result := make([]string, 0) a := &arg{ - result: &result, - sname: short, - lname: long, - size: 2, - opts: opts, - unique: false, + result: &result, + sname: short, + lname: long, + size: 2, + opts: opts, + unique: false, + argType: StringList, } if err := o.addArg(a); err != nil { @@ -367,12 +439,13 @@ func (o *Command) IntList(short string, long string, opts *Options) *[]int { result := make([]int, 0) a := &arg{ - result: &result, - sname: short, - lname: long, - size: 2, - opts: opts, - unique: false, + result: &result, + sname: short, + lname: long, + size: 2, + opts: opts, + unique: false, + argType: IntList, } if err := o.addArg(a); err != nil { @@ -390,12 +463,13 @@ func (o *Command) FloatList(short string, long string, opts *Options) *[]float64 result := make([]float64, 0) a := &arg{ - result: &result, - sname: short, - lname: long, - size: 2, - opts: opts, - unique: false, + result: &result, + sname: short, + lname: long, + size: 2, + opts: opts, + unique: false, + argType: FloatList, } if err := o.addArg(a); err != nil { @@ -421,6 +495,7 @@ func (o *Command) FileList(short string, long string, flag int, perm os.FileMode unique: false, fileFlag: flag, filePerm: perm, + argType: FileList, } if err := o.addArg(a); err != nil { @@ -447,6 +522,7 @@ func (o *Command) Selector(short string, long string, options []string, opts *Op opts: opts, unique: true, selector: &options, + argType: Selector, } if err := o.addArg(a); err != nil { @@ -456,6 +532,18 @@ func (o *Command) Selector(short string, long string, options []string, opts *Op return &result } +// See func Selector documentation +func (o *Command) SelectorPositional(allowed []string, opts *Options) *string { + if opts == nil { + opts = &Options{} + } + opts.positional = true + + // We supply a long name for documentation and internal logic + name := fmt.Sprintf(positionalArgName, o.name, len(o.args)) + return o.Selector("", name, allowed, opts) +} + // message2String puts msg in result string // done boolean indicates if result is ready to be returned // Accepts an interface that can be error, string or fmt.Stringer that will be prepended to a message. @@ -682,12 +770,16 @@ func (o *Parser) Parse(args []string) error { copy(subargs, args) result := o.parse(&subargs) + if result == nil { + result = o.parsePositionals(&subargs) + } unparsed := make([]string, 0) for _, v := range subargs { if v != "" { unparsed = append(unparsed, v) } } + if result == nil && len(unparsed) > 0 { return errors.New("unknown arguments " + strings.Join(unparsed, " ")) } diff --git a/vendor/github.com/akamensky/argparse/argument.go b/vendor/github.com/akamensky/argparse/argument.go index 9b5aed3..d0c52eb 100644 --- a/vendor/github.com/akamensky/argparse/argument.go +++ b/vendor/github.com/akamensky/argparse/argument.go @@ -9,25 +9,57 @@ import ( ) type arg struct { - result interface{} // Pointer to the resulting value - opts *Options // Options - sname string // Short name (in Parser will start with "-" - lname string // Long name (in Parser will start with "--" - size int // Size defines how many args after match will need to be consumed - unique bool // Specifies whether flag should be present only ones - parsed bool // Specifies whether flag has been parsed already - fileFlag int // File mode to open file with - filePerm os.FileMode // File permissions to set a file - selector *[]string // Used in Selector type to allow to choose only one from list of options - parent *Command // Used to get access to specific Command - eqChar bool // This is used if the command is passed in with an equals char as a seperator + result interface{} // Pointer to the resulting value + opts *Options // Options + sname string // Short name (in Parser will start with "-" + lname string // Long name (in Parser will start with "--" + size int // Size defines how many args after match will need to be consumed + unique bool // Specifies whether flag should be present only once + parsed bool // Specifies whether flag has been parsed already + fileFlag int // File mode to open file with + filePerm os.FileMode // File permissions to set a file + selector *[]string // Used in Selector type to allow to choose only one from list of options + parent *Command // Used to get access to specific Command + eqChar bool // This is used if the command is passed in with an equals char as a seperator + argType ArgumentType // Used to determine which argument type this is } +// enum used to determine the argument type +type ArgumentType int + +const ( + Flag ArgumentType = 0 + FlagCounter = 1 + String = 2 + Int = 3 + Float = 4 + File = 5 + StringList = 6 + IntList = 7 + FloatList = 8 + FileList = 9 + Selector = 10 +) + // Arg interface provides exporting of arg structure, while exposing it type Arg interface { GetOpts() *Options GetSname() string GetLname() string + GetResult() interface{} + GetPositional() bool + GetParsed() bool +} + +func (o arg) GetPositional() bool { + if o.opts != nil { + return o.opts.positional + } + return false +} + +func (o arg) GetParsed() bool { + return o.parsed } func (o arg) GetOpts() *Options { @@ -42,6 +74,12 @@ func (o arg) GetLname() string { return o.lname } +// getResult returns the interface{} to the *(type) containing the argument's result value +// Will contain the empty/default value if argument value was not given +func (o arg) GetResult() interface{} { + return o.result +} + type help struct{} // checkLongName if long argumet present. @@ -61,7 +99,7 @@ func (o *arg) checkLongName(argument string) int { return 0 } -// checkShortName if argumet present. +// checkShortName if argument present. // checkShortName - returns the argumet's short name number of occurrences and error. // For shorthand argument - 0 if there is no occurrences, or count of occurrences. // Shorthand argument with parametr, mast be the only or last in the argument string. @@ -94,8 +132,8 @@ func (o *arg) checkShortName(argument string) (int, error) { return 0, nil } -// check if argumet present. -// check - returns the argumet's number of occurrences and error. +// check if argument present. +// check - returns the argument's number of occurrences and error. // For long name return value is 0 or 1. // For shorthand argument - 0 if there is no occurrences, or count of occurrences. // Shorthand argument with parametr, mast be the only or last in the argument string. @@ -108,6 +146,10 @@ func (o *arg) check(argument string) (int, error) { return o.checkShortName(argument) } +func (o *arg) reducePositional(position int, args *[]string) { + (*args)[position] = "" +} + func (o *arg) reduceLongName(position int, args *[]string) { argument := (*args)[position] // Check for long name only if not empty @@ -159,8 +201,12 @@ func (o *arg) reduceShortName(position int, args *[]string) { // clear out already used argument from args at position func (o *arg) reduce(position int, args *[]string) { - o.reduceLongName(position, args) - o.reduceShortName(position, args) + if o.GetPositional() { + o.reducePositional(position, args) + } else { + o.reduceLongName(position, args) + o.reduceShortName(position, args) + } } func (o *arg) parseInt(args []string, argCount int) error { @@ -375,23 +421,34 @@ func (o *arg) parseSomeType(args []string, argCount int) error { return err } +func (o *arg) parsePositional(arg string) error { + if err := o.parse([]string{arg}, 1); err != nil { + return err + } + + return nil +} + func (o *arg) parse(args []string, argCount int) error { // If unique do not allow more than one time if o.unique && (o.parsed || argCount > 1) { return fmt.Errorf("[%s] can only be present once", o.name()) } - // If validation function provided -- execute, on error return it immediately + // If validation function provided -- execute, on error return immediately if o.opts != nil && o.opts.Validate != nil { err := o.opts.Validate(args) if err != nil { - return err + return fmt.Errorf("[%s] %w", o.name(), err) } } return o.parseSomeType(args, argCount) } func (o *arg) name() string { + if o.GetPositional() { + return o.lname + } var name string if o.lname == "" { name = "-" + o.sname @@ -410,7 +467,10 @@ func (o *arg) usage() string { case *bool: break case *int: - result = result + " " + isFlagCounter := !o.unique && o.size == 1 + if !isFlagCounter { + result = result + " " + } case *float64: result = result + " " case *string: @@ -499,7 +559,11 @@ func (o *arg) setDefault() error { if reflect.TypeOf(o.result) != reflect.PtrTo(reflect.TypeOf(o.opts.Default)) { return fmt.Errorf("cannot use default type [%T] as value of pointer with type [%T]", o.opts.Default, o.result) } - reflect.ValueOf(o.result).Elem().Set(reflect.ValueOf(o.opts.Default)) + defaultValue := o.opts.Default + if o.argType == Flag && defaultValue == true { + defaultValue = false + } + reflect.ValueOf(o.result).Elem().Set(reflect.ValueOf(defaultValue)) case *os.File: if err := o.setDefaultFile(); err != nil { diff --git a/vendor/github.com/akamensky/argparse/command.go b/vendor/github.com/akamensky/argparse/command.go index 7bccf3b..f87d411 100644 --- a/vendor/github.com/akamensky/argparse/command.go +++ b/vendor/github.com/akamensky/argparse/command.go @@ -51,7 +51,18 @@ func (o *Command) addArg(a *arg) error { current = current.parent } a.parent = o + + if a.GetPositional() { + switch a.argType { // Secondary guard + case Flag, FlagCounter, StringList, IntList, FloatList, FileList: + return fmt.Errorf("argument type cannot be positional") + } + a.sname = "" + a.opts.Required = false + a.size = 1 // We could allow other sizes in the future + } o.args = append(o.args, a) + return nil } @@ -68,18 +79,65 @@ func (o *Command) parseSubCommands(args *[]string) error { if err != nil { return err } + if v.happened { + return nil + } + } + // If we got here, there were subcommands to parse, + // but none were found, so return an error + return newSubCommandError(o) + } + return nil +} + +// Breadth-first parse style for positionals +// Each command proceeds left to right consuming as many +// positionals as it needs before beginning sub-command parsing +// All flags must have been parsed and reduced prior to calling this +// Positionals will consume any remaining values, +// disregarding if they have dashes or equals signs or other "delims". +func (o *Command) parsePositionals(inputArgs *[]string) error { + for _, oarg := range o.args { + // Two-stage parsing, this is the second stage + if !oarg.GetPositional() { + continue + } + for j := 0; j < len(*inputArgs); j++ { + arg := (*inputArgs)[j] + if arg == "" { + continue + } + if err := oarg.parsePositional(arg); err != nil { + return err + } + oarg.reduce(j, inputArgs) + break // Positionals can only occur once + } + // positional was unsatisfiable, use the default + if !oarg.parsed { + err := oarg.setDefault() + if err != nil { + return err + } + } + } + for _, c := range o.commands { + if c.happened { // presumption of only one sub-command happening + return c.parsePositionals(inputArgs) } } return nil } //parseArguments - Parses arguments -func (o *Command) parseArguments(args *[]string) error { +func (o *Command) parseArguments(inputArgs *[]string) error { // Iterate over the args - for i := 0; i < len(o.args); i++ { - oarg := o.args[i] - for j := 0; j < len(*args); j++ { - arg := (*args)[j] + for _, oarg := range o.args { + if oarg.GetPositional() { // Two-stage parsing, this is the first stage + continue + } + for j := 0; j < len(*inputArgs); j++ { + arg := (*inputArgs)[j] if arg == "" { continue } @@ -88,7 +146,7 @@ func (o *Command) parseArguments(args *[]string) error { equalArg := []string{arg[:splitInd], arg[splitInd+1:]} if cnt, err := oarg.check(equalArg[0]); err != nil { return err - } else if cnt > 0 { + } else if cnt > 0 { // No args implies we supply default if equalArg[1] == "" { return fmt.Errorf("not enough arguments for %s", oarg.name()) } @@ -99,21 +157,21 @@ func (o *Command) parseArguments(args *[]string) error { if err != nil { return err } - oarg.reduce(j, args) + oarg.reduce(j, inputArgs) continue } } if cnt, err := oarg.check(arg); err != nil { return err } else if cnt > 0 { - if len(*args) < j+oarg.size { + if len(*inputArgs) < j+oarg.size { return fmt.Errorf("not enough arguments for %s", oarg.name()) } - err := oarg.parse((*args)[j+1:j+oarg.size], cnt) + err := oarg.parse((*inputArgs)[j+1:j+oarg.size], cnt) if err != nil { return err } - oarg.reduce(j, args) + oarg.reduce(j, inputArgs) continue } } @@ -121,10 +179,8 @@ func (o *Command) parseArguments(args *[]string) error { // Check if arg is required and not provided if oarg.opts != nil && oarg.opts.Required && !oarg.parsed { return fmt.Errorf("[%s] is required", oarg.name()) - } - - // Check for argument default value and if provided try to type cast and assign - if oarg.opts != nil && oarg.opts.Default != nil && !oarg.parsed { + } else if oarg.opts != nil && oarg.opts.Default != nil && !oarg.parsed { + // Check for argument default value and if provided try to type cast and assign err := oarg.setDefault() if err != nil { return err @@ -136,8 +192,11 @@ func (o *Command) parseArguments(args *[]string) error { // Will parse provided list of arguments // common usage would be to pass directly os.Args +// Depth-first parsing: We will reach the deepest +// node of the command tree and then parse arguments, +// stepping back up only after each node is satisfied. func (o *Command) parse(args *[]string) error { - // If we already been parsed do nothing + // If already been parsed do nothing if o.parsed { return nil } @@ -157,7 +216,7 @@ func (o *Command) parse(args *[]string) error { } } - // Set happened status to true when command happend + // Set happened status to true when command happened o.happened = true // Reduce arguments by removing Command name diff --git a/vendor/github.com/akamensky/argparse/misc.go b/vendor/github.com/akamensky/argparse/misc.go new file mode 100644 index 0000000..bc9af6d --- /dev/null +++ b/vendor/github.com/akamensky/argparse/misc.go @@ -0,0 +1,13 @@ +package argparse + +import ( + "os" + "reflect" +) + +// IsNilFile allows to test whether returned `*os.File` has been initialized with data passed on CLI. +// Returns true if `fd == &{nil}`, which means `*os.File` was not initialized, false if `fd` is +// a fully initialized `*os.File` or if `fd == nil`. +func IsNilFile(fd *os.File) bool { + return reflect.DeepEqual(fd, &os.File{}) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 151c066..d9901da 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,7 +1,7 @@ # github.com/BurntSushi/toml v0.3.1 ## explicit github.com/BurntSushi/toml -# github.com/akamensky/argparse v1.2.2 +# github.com/akamensky/argparse v1.4.0 ## explicit github.com/akamensky/argparse # github.com/beevik/etree v1.1.0