You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
2.6 KiB
142 lines
2.6 KiB
4 years ago
|
package console
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"os"
|
||
|
|
||
|
"gitoa.ru/go-4devs/console/input"
|
||
|
"gitoa.ru/go-4devs/console/input/argv"
|
||
|
"gitoa.ru/go-4devs/console/input/value"
|
||
|
"gitoa.ru/go-4devs/console/output"
|
||
|
"gitoa.ru/go-4devs/console/output/writer"
|
||
|
)
|
||
|
|
||
|
// 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: writer.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 = argv.New(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
|
||
|
}
|
||
|
|
||
|
a.in.SetArgument("command_name", value.New(CommandList))
|
||
|
|
||
|
return Run(ctx, cmd, a.in, a.out)
|
||
|
}
|
||
|
|
||
|
func (a *App) printError(ctx context.Context, err error) {
|
||
|
a.out.Println(ctx, "<error>\n\n ", err, "\n</error>")
|
||
|
}
|