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.

147 lines
3.5 KiB

4 years ago
package console
import (
"context"
"errors"
"os"
"gitoa.ru/go-4devs/console/input"
"gitoa.ru/go-4devs/console/input/option"
"gitoa.ru/go-4devs/console/input/value"
"gitoa.ru/go-4devs/console/output"
"gitoa.ru/go-4devs/console/output/verbosity"
)
const (
verboseTrace = 3
verboseDebug = 2
verboseInfo = 1
4 years ago
)
const (
OptionHelp = "help"
OptionVersion = "version"
OptionAnsi = "ansi"
OptionNoAnsi = "no-ansi"
OptionQuiet = "quiet"
OptionVerbose = "verbose"
)
4 years ago
// Execute the current command with option.
func Execute(ctx context.Context, cmd *Command, opts ...func(*App)) {
opts = append([]func(*App){WithSkipArgs(1)}, opts...)
New(opts...).exec(ctx, cmd)
}
// Run current command by input and output.
4 years ago
func Run(ctx context.Context, cmd *Command, in input.Input, out output.Output) error {
def := input.NewDefinition()
if err := cmd.Init(ctx, def); err != nil {
return err
}
if err := in.Bind(ctx, Default(def)); err != nil {
ansi(ctx, in, out).Print(ctx, "<error>\n\n ", err, "\n</error>\n")
return showHelp(ctx, cmd, in, output.Ansi(out))
4 years ago
}
out = ansi(ctx, in, out)
out = verbose(ctx, in, out)
if in.Option(ctx, OptionVersion).Bool() {
4 years ago
version := cmd.Version
if version == "" {
version = "unknown"
}
out.Println(ctx, "command <comment>", cmd.Name, "</comment> version: <info>", version, "</info>")
return nil
}
if in.Option(ctx, OptionHelp).Bool() {
4 years ago
return showHelp(ctx, cmd, in, out)
}
return cmd.Run(ctx, in, out)
}
func ansi(ctx context.Context, in input.Input, out output.Output) output.Output {
switch {
case in.Option(ctx, OptionAnsi).Bool():
out = output.Ansi(out)
case in.Option(ctx, OptionNoAnsi).Bool():
out = output.None(out)
4 years ago
case lookupEnv("NO_COLOR"):
out = output.None(out)
4 years ago
default:
out = output.Ansi(out)
4 years ago
}
return out
}
func lookupEnv(name string) bool {
v, has := os.LookupEnv(name)
return has && v == "true"
}
func verbose(ctx context.Context, in input.Input, out output.Output) output.Output {
switch {
case in.Option(ctx, OptionQuiet).Bool():
out = output.Quiet()
4 years ago
default:
verb := in.Option(ctx, OptionVerbose).Bools()
4 years ago
switch {
case len(verb) == verboseInfo:
out = output.Verbosity(out, verbosity.Info)
case len(verb) == verboseDebug:
out = output.Verbosity(out, verbosity.Debug)
case len(verb) >= verboseTrace:
out = output.Verbosity(out, verbosity.Trace)
4 years ago
default:
out = output.Verbosity(out, verbosity.Norm)
4 years ago
}
}
return out
}
func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Output) error {
arr := &input.Array{}
arr.SetArgument(ArgumentCommandName, value.New(cmd.Name))
arr.SetOption(OptionHelp, value.New(false))
4 years ago
if _, err := Find(cmd.Name); errors.Is(err, ErrNotFound) {
register(cmd)
}
help, err := Find(CommandHelp)
if err != nil {
return err
}
4 years ago
w := input.Chain(arr, in)
4 years ago
return Run(ctx, help, w, out)
4 years ago
}
// Default options and argument command.
func Default(d *input.Definition) *input.Definition {
return d.SetOptions(
option.Bool(OptionNoAnsi, "Disable ANSI output"),
option.Bool(OptionAnsi, "Do not ask any interactive question"),
option.Bool(OptionVersion, "Display this application version", option.Short('V')),
option.Bool(OptionHelp, "Display this help message", option.Short('h')),
option.Bool(OptionVerbose,
4 years ago
"Increase the verbosity of messages: -v for info output, -vv for debug and -vvv for trace",
option.Short('v'), option.Array),
option.Bool(OptionQuiet, "Do not output any message", option.Short('q')),
4 years ago
)
}