package command import ( "errors" "fmt" "strings" ) var ( ErrWrongCommand = errors.New("wrong command") ErrInvalidArg = errors.New("invalid argument") ) type ArgSet struct { Main string Flags map[string]string } func (as *ArgSet) HasFlag(name string) bool { _, ok := as.Flags[name] return ok } func (as *ArgSet) Flag(name string) string { return as.Flags[name] } func (as *ArgSet) SetFlag(name, value string) { as.Flags[name] = value } type Command interface { Parse(args []string) (*ArgSet, error) Do(args *ArgSet) error } type CLI struct { Commands []Command } func (cli *CLI) Run(args []string) error { for _, c := range cli.Commands { as, err := c.Parse(args) switch { case errors.Is(err, ErrWrongCommand): continue case err != nil: return err default: return c.Do(as) } } return fmt.Errorf("could not find matching command") } func ParseArgs(args []string) (*ArgSet, error) { flags := make(map[string]string) main := make([]string, 0) var inMain bool for i := 0; i < len(args); i++ { if strings.HasPrefix(args[i], "-") { inMain = false if i+1 >= len(args) { return &ArgSet{}, fmt.Errorf("flag wihout value") } flags[strings.TrimPrefix(args[i], "-")] = args[i+1] i++ continue } if !inMain && len(main) > 0 { return &ArgSet{}, fmt.Errorf("two mains") } inMain = true main = append(main, args[i]) } return &ArgSet{ Main: strings.Join(main, " "), Flags: flags, }, nil }