package parser import ( "os" "fmt" "git.arcanium.tech/tristan/logging" ) type App struct { Name string Commands []*Command Flags []*ArgFlag } func (a *App) addRootCommand(cmd *Command){ a.Commands = append(a.Commands, cmd) } func (a *App) NewRootCommand(info CommandOptions) *Command { cmd := &Command{ Name: info.Name, Description: info.Description, } a.addRootCommand( cmd ) return cmd } func (a *App) Help() { appHelpTemplate.Execute(os.Stdout, a) } func (a *App) getFlag(name string) (*ArgFlag, error) { for _, flag := range a.Flags { if flag.Matches(name) { return flag, nil } } return nil, fmt.Errorf("App(%s) : ERROR : there is no flag by name %s", a.Name, name) } func (a *App) isCommand(name string) bool { for _, command := range a.Commands { if command.Name == name { return true } } return false } func (a *App) getCommand(name string) (*Command, error) { for _, command := range a.Commands { if command.Name == name { return command, nil } } return nil, fmt.Errorf("App(%s) : ERROR : No command named \"%s\"", a.Name, name) } func (a *App) determineMatch(arg string) (matchType, error) { if arg == "-h" || arg == "--help" || arg == "help" { return helpMatch, nil } flag_match, err := isFlag(arg) if err != nil { return noMatch, err } if flag_match { return flagMatch, nil } command := a.isCommand(arg) if command == true { return commandMatch, nil } return noMatch, nil } func (a *App) doChecks() error { for _, command := range a.Commands{ err := command.Check() if err != nil { return err } } for _, flag := range a.Flags { err := flag.Check() if err != nil { return err } } return nil } func (a *App) registerSelf(commands []*Command) { for _, command := range commands { command.App = a if len(command.SubCommands) > 0 { a.registerSelf(command.SubCommands) } } } func (a *App) Run(args []string) error { logging.Debug("App(%s) : Beginning Run", a.Name) a.registerSelf(a.Commands) err := a.doChecks() if err != nil { return err } if len(args) == 0 { a.Help() return nil } for i := 0; i < len(args); i++ { arg := args[i] logging.Debug("App(%s) : Iterating on provided args (i: %d, arg: %s)", a.Name, i, arg) remaining_args := args[i+1:] match, err := a.determineMatch(arg) if err != nil { return err } switch match { case noMatch: return fmt.Errorf("No match found for Arg(%s) for App(%s)", arg, a.Name) case helpMatch: a.Help() return nil case flagMatch: flag, err := a.getFlag(arg) if err != nil { return err } if flag.requireArg(){ if len(args[i:]) <= 1 { return fmt.Errorf("Command(%s) : ArgFlag(%s) : Required argument not found", a.Name, flag.Name) } arglist := args[i:i+2] i++ // want to call the flag with itself & the argument it wants err = flag.CheckArg(arglist) if err != nil { return err } } else { // Since we want to preserve that they were called at all. (particularly for BoolType) flag.Args = args[i:i+1] } if flag.OnMatch != nil { err := flag.OnMatch() if err != nil { return err } } case commandMatch: command, err := a.getCommand(arg) if err != nil { return err } return command.Run(remaining_args) } } return nil }