package console import ( "context" "os" "gitoa.ru/go-4devs/console/input" "gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/output" ) // WithOutput sets outpu,^ by default output os.Stdout. func WithOutput(out output.Output) func(*App) { return func(a *App) { a.out = out } } // WithInput sets input, by default creates inpur by os.Args. func WithInput(in input.Input) func(*App) { return func(a *App) { a.in = in } } // WithSkipArgs sets how many arguments are passed. For example, you don't need to pass the name of a single command. func WithSkipArgs(l int) func(*App) { return func(a *App) { a.skipArgv = l } } // WithExit sets exit callback by default os.Exit. func WithExit(f func(int)) func(*App) { return func(a *App) { a.exit = f } } // New creates and configure new console app. func New(opts ...func(*App)) *App { a := &App{ out: output.Stdout(), exit: os.Exit, } for _, opt := range opts { opt(a) } if a.in == nil { skip := 2 switch { case a.skipArgv > 0 && len(os.Args) > a.skipArgv: skip = a.skipArgv case a.skipArgv > 0: skip = len(os.Args) case len(os.Args) == 1: skip = 1 case len(os.Args) > 1 && os.Args[1][0] == '-': skip = 1 } a.in = &input.Argv{ Args: os.Args[skip:], } } return a } // App is collection of command and configure env. type App struct { cmds []*Command out output.Output in input.Input skipArgv int exit func(int) } // Add add or replace command. func (a *App) Add(cmds ...*Command) *App { a.cmds = append(a.cmds, cmds...) return a } // Execute run the command by name and arguments. func (a *App) Execute(ctx context.Context) { for _, cmd := range a.cmds { register(cmd) } cmd, err := a.find(ctx) if err != nil { a.printError(ctx, err) if err := a.list(ctx); err != nil { a.printError(ctx, err) } a.exit(1) } a.exec(ctx, cmd) } func (a *App) exec(ctx context.Context, cmd *Command) { if err := Run(ctx, cmd, a.in, a.out); err != nil { a.printError(ctx, err) a.exit(1) } a.exit(0) } func (a *App) find(_ context.Context) (*Command, error) { if len(os.Args) < 2 || os.Args[1][1] == '-' { return Find(CommandList) } name := os.Args[1] return Find(name) } func (a *App) list(ctx context.Context) error { cmd, err := Find(CommandHelp) if err != nil { return err } in := &input.Wrap{ Input: a.in, } in.SetArgument("command_name", value.New(CommandList)) return Run(ctx, cmd, in, a.out) } func (a *App) printError(ctx context.Context, err error) { a.out.Println(ctx, "\n\n ", err, "\n") }