addFlags adds to given the given ordered flags map all of the different ways all of the given fields can can be specified as flags. It also uses the given positional arguments to set the values of the object based on any posarg struct tags that fields have. The posarg struct tag must either be "all"
(allFields *fields, allFlags *fields, args []string, flags map[string]string)
| 411 | // or a valid uint. Finally, it also uses the given map of flags passed to the |
| 412 | // command as context. |
| 413 | func addFlags(allFields *fields, allFlags *fields, args []string, flags map[string]string) ([]string, error) { |
| 414 | consumed := map[int]bool{} // which args we have consumed via pos args |
| 415 | var leftoverField *field |
| 416 | for _, kv := range allFields.Order { |
| 417 | v := kv.Value |
| 418 | f := v.Field |
| 419 | |
| 420 | for _, name := range v.Names { |
| 421 | addAllCases(name, v, allFlags) |
| 422 | if f.Type.Kind() == reflect.Bool { |
| 423 | addAllCases("No"+name, v, allFlags) |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | // set based on pos arg |
| 428 | posArgTag, ok := f.Tag.Lookup("posarg") |
| 429 | if ok { |
| 430 | switch posArgTag { |
| 431 | case "all": |
| 432 | err := reflectx.SetRobust(v.Value.Interface(), args) |
| 433 | if err != nil { |
| 434 | return nil, fmt.Errorf("error setting field %q to all positional arguments: %v: %w", f.Name, args, err) |
| 435 | } |
| 436 | // everybody has been consumed |
| 437 | for i := range args { |
| 438 | consumed[i] = true |
| 439 | } |
| 440 | case "leftover": |
| 441 | leftoverField = v // must be handled later once we have all of the leftovers |
| 442 | default: |
| 443 | ui, err := strconv.ParseUint(posArgTag, 10, 64) |
| 444 | if err != nil { |
| 445 | return nil, fmt.Errorf("programmer error: invalid value %q for posarg struct tag on field %q: %w", posArgTag, f.Name, err) |
| 446 | } |
| 447 | // if this is true, the pos arg is missing |
| 448 | if ui >= uint64(len(args)) { |
| 449 | // if it isn't required, it doesn't matter if it's missing |
| 450 | req, has := f.Tag.Lookup("required") |
| 451 | if req != "+" && req != "true" && has { // default is required, so !has => required |
| 452 | continue |
| 453 | } |
| 454 | // check if we have set this pos arg as a flag; if we have, |
| 455 | // it makes up for the missing pos arg and there is no error, |
| 456 | // but otherwise there is an error |
| 457 | got := false |
| 458 | for _, fnm := range v.Names { // TODO: is there a more efficient way to do this? |
| 459 | for _, cnm := range allCases(fnm) { |
| 460 | _, ok := flags[cnm] |
| 461 | if ok { |
| 462 | got = true |
| 463 | break |
| 464 | } |
| 465 | } |
| 466 | if got { |
| 467 | break |
| 468 | } |
| 469 | } |
| 470 | if got { |