add processSingle and make it responsible for checking whether an argument has been seen before
This commit is contained in:
parent
64288c5521
commit
b365ec0781
|
@ -404,7 +404,7 @@ func Example_errorText() {
|
||||||
|
|
||||||
// output:
|
// output:
|
||||||
// Usage: example [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] INPUT [OUTPUT [OUTPUT ...]]
|
// Usage: example [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] INPUT [OUTPUT [OUTPUT ...]]
|
||||||
// error: error processing --optimize: strconv.ParseInt: parsing "INVALID": invalid syntax
|
// error: error processing default value for --optimize: strconv.ParseInt: parsing "INVALID": invalid syntax
|
||||||
}
|
}
|
||||||
|
|
||||||
// This example shows the error string generated by go-arg when an invalid option is provided
|
// This example shows the error string generated by go-arg when an invalid option is provided
|
||||||
|
@ -428,7 +428,7 @@ func Example_errorTextForSubcommand() {
|
||||||
|
|
||||||
// output:
|
// output:
|
||||||
// Usage: example get [--count COUNT]
|
// Usage: example get [--count COUNT]
|
||||||
// error: error processing --count: strconv.ParseInt: parsing "INVALID": invalid syntax
|
// error: error processing default value for --count: strconv.ParseInt: parsing "INVALID": invalid syntax
|
||||||
}
|
}
|
||||||
|
|
||||||
// This example demonstrates use of subcommands
|
// This example demonstrates use of subcommands
|
||||||
|
|
108
v2/parse.go
108
v2/parse.go
|
@ -207,29 +207,8 @@ func (p *Parser) processOptions(args []string, overwrite bool) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// deal with the case of multiple values
|
// deal with the case of multiple values
|
||||||
if arg.cardinality == multiple {
|
if arg.cardinality == multiple && !arg.separate {
|
||||||
// if arg.separate is true then just parse one value and append it
|
// consume tokens until next --option
|
||||||
if arg.separate {
|
|
||||||
if value == "" {
|
|
||||||
if i+1 == len(args) {
|
|
||||||
return nil, fmt.Errorf("missing value for %s", token)
|
|
||||||
}
|
|
||||||
if isFlag(args[i+1]) {
|
|
||||||
return nil, fmt.Errorf("missing value for %s", token)
|
|
||||||
}
|
|
||||||
value = args[i+1]
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
err := appendToSliceOrMap(p.val(arg.dest), value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error processing %s: %v", token, err)
|
|
||||||
}
|
|
||||||
p.seen[arg] = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// if args.separate is not true then consume tokens until next --option
|
|
||||||
var values []string
|
var values []string
|
||||||
if value == "" {
|
if value == "" {
|
||||||
for i+1 < len(args) && !isFlag(args[i+1]) && args[i+1] != "--" {
|
for i+1 < len(args) && !isFlag(args[i+1]) && args[i+1] != "--" {
|
||||||
|
@ -240,6 +219,8 @@ func (p *Parser) processOptions(args []string, overwrite bool) ([]string, error)
|
||||||
values = append(values, value)
|
values = append(values, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: call p.processVector
|
||||||
|
|
||||||
// this is the first time we can check p.seen because we need to correctly
|
// this is the first time we can check p.seen because we need to correctly
|
||||||
// increment i above, even when we then ignore the value
|
// increment i above, even when we then ignore the value
|
||||||
if p.seen[arg] && !overwrite {
|
if p.seen[arg] && !overwrite {
|
||||||
|
@ -251,6 +232,8 @@ func (p *Parser) processOptions(args []string, overwrite bool) ([]string, error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error processing %s: %v", token, err)
|
return nil, fmt.Errorf("error processing %s: %v", token, err)
|
||||||
}
|
}
|
||||||
|
p.seen[arg] = true
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,17 +255,10 @@ func (p *Parser) processOptions(args []string, overwrite bool) ([]string, error)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is the first time we can check p.seen because we need to correctly
|
// send the value to the argument
|
||||||
// increment i above, even when we then ignore the value
|
if err := p.processSingle(arg, value, overwrite); err != nil {
|
||||||
if p.seen[arg] && !overwrite {
|
return nil, err
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := scalar.ParseValue(p.val(arg.dest), value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error processing %s: %v", token, err)
|
|
||||||
}
|
|
||||||
p.seen[arg] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return positionals, nil
|
return positionals, nil
|
||||||
|
@ -311,23 +287,21 @@ func (p *Parser) processPositionals(positionals []string, overwrite bool) error
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if arg.cardinality == multiple {
|
if arg.cardinality == multiple {
|
||||||
|
// TODO: call p.processMultiple
|
||||||
if !p.seen[arg] || overwrite {
|
if !p.seen[arg] || overwrite {
|
||||||
err := setSliceOrMap(p.val(arg.dest), positionals)
|
err := setSliceOrMap(p.val(arg.dest), positionals)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error processing %s: %v", arg.field.Name, err)
|
return fmt.Errorf("error processing %s: %v", arg.field.Name, err)
|
||||||
}
|
}
|
||||||
|
p.seen[arg] = true
|
||||||
}
|
}
|
||||||
positionals = nil
|
positionals = nil
|
||||||
} else {
|
} else {
|
||||||
if !p.seen[arg] || overwrite {
|
if err := p.processSingle(arg, positionals[0], overwrite); err != nil {
|
||||||
err := scalar.ParseValue(p.val(arg.dest), positionals[0])
|
return err
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error processing %s: %v", arg.field.Name, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
positionals = positionals[1:]
|
positionals = positionals[1:]
|
||||||
}
|
}
|
||||||
p.seen[arg] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(positionals) > 0 {
|
if len(positionals) > 0 {
|
||||||
|
@ -364,10 +338,6 @@ func (p *Parser) processEnvironment(environ []string, overwrite bool) error {
|
||||||
|
|
||||||
// process arguments one-by-one
|
// process arguments one-by-one
|
||||||
for _, arg := range p.accumulatedArgs {
|
for _, arg := range p.accumulatedArgs {
|
||||||
if p.seen[arg] && !overwrite {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if arg.env == "" {
|
if arg.env == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -377,7 +347,7 @@ func (p *Parser) processEnvironment(environ []string, overwrite bool) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg.cardinality == multiple {
|
if arg.cardinality == multiple && !arg.separate {
|
||||||
// expect a CSV string in an environment
|
// expect a CSV string in an environment
|
||||||
// variable in the case of multiple values
|
// variable in the case of multiple values
|
||||||
var values []string
|
var values []string
|
||||||
|
@ -385,28 +355,20 @@ func (p *Parser) processEnvironment(environ []string, overwrite bool) error {
|
||||||
if len(strings.TrimSpace(value)) > 0 {
|
if len(strings.TrimSpace(value)) > 0 {
|
||||||
values, err = csv.NewReader(strings.NewReader(value)).Read()
|
values, err = csv.NewReader(strings.NewReader(value)).Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error reading a CSV string from environment variable %s : %v", arg.env, err)
|
return fmt.Errorf("error parsing CSV string from environment variable %s: %v", arg.env, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if arg.separate {
|
// TODO: call p.processMultiple, respect "overwrite"
|
||||||
if err = setSliceOrMap(p.val(arg.dest), values); err != nil {
|
if err = setSliceOrMap(p.val(arg.dest), values); err != nil {
|
||||||
return fmt.Errorf("error processing environment variable %s: %v", arg.env, err)
|
return fmt.Errorf("error processing environment variable %s: %v", arg.env, err)
|
||||||
}
|
}
|
||||||
} else {
|
continue
|
||||||
for _, s := range values {
|
|
||||||
if err = appendToSliceOrMap(p.val(arg.dest), s); err != nil {
|
|
||||||
return fmt.Errorf("error processing environment variable %s: %v", arg.env, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := scalar.ParseValue(p.val(arg.dest), value); err != nil {
|
|
||||||
return fmt.Errorf("error processing environment variable %s: %v", arg.env, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.seen[arg] = true
|
if err := p.processSingle(arg, value, overwrite); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -428,26 +390,44 @@ func (p *Parser) OverwriteWithDefaults() error {
|
||||||
// If overwrite is true then it overwrites existing values.
|
// If overwrite is true then it overwrites existing values.
|
||||||
func (p *Parser) processDefaults(overwrite bool) error {
|
func (p *Parser) processDefaults(overwrite bool) error {
|
||||||
for _, arg := range p.accumulatedArgs {
|
for _, arg := range p.accumulatedArgs {
|
||||||
if p.seen[arg] && !overwrite {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if arg.defaultVal == "" {
|
if arg.defaultVal == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err := p.processSingle(arg, arg.defaultVal, overwrite); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// processSingle parses a single argument, inserts it into the struct,
|
||||||
|
// and marks the argument as "seen" for the sake of required arguments
|
||||||
|
// and overwrite semantics. If the argument has been seen before and
|
||||||
|
// overwrite=false then the value is ignored.
|
||||||
|
func (p *Parser) processSingle(arg *Argument, value string, overwrite bool) error {
|
||||||
|
if p.seen[arg] && !overwrite && !arg.separate {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
name := strings.ToLower(arg.field.Name)
|
name := strings.ToLower(arg.field.Name)
|
||||||
if arg.long != "" && !arg.positional {
|
if arg.long != "" && !arg.positional {
|
||||||
name = "--" + arg.long
|
name = "--" + arg.long
|
||||||
}
|
}
|
||||||
|
|
||||||
err := scalar.ParseValue(p.val(arg.dest), arg.defaultVal)
|
if arg.cardinality == multiple {
|
||||||
|
err := appendToSliceOrMap(p.val(arg.dest), value)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error processing default value for %s: %v", name, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err := scalar.ParseValue(p.val(arg.dest), value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error processing default value for %s: %v", name, err)
|
return fmt.Errorf("error processing default value for %s: %v", name, err)
|
||||||
}
|
}
|
||||||
p.seen[arg] = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.seen[arg] = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue