package cmd import ( "fmt" "os" "path/filepath" "go.fifitido.net/cmd/opt" ) type Command struct { name string shortDescription string longDescription string aliases []string arguments []*Argument opts opt.Set subcommands Set parent *Command run func(args []string) isRoot bool } func NewRoot(options ...Option) *Command { cmd := &Command{isRoot: true} cmd.ApplyOptions(options...) return cmd } func New(name string, options ...Option) *Command { cmd := &Command{name: name} cmd.ApplyOptions(options...) return cmd } func (c *Command) ApplyOptions(options ...Option) { for _, option := range options { option(c) } } func (c *Command) Root() *Command { if c.isRoot { return c } return c.parent.Root() } func (c *Command) CommandPath() string { if c.parent == nil { return filepath.Base(os.Args[0]) } return c.parent.CommandPath() + " " + c.name } func (c *Command) CanRun() bool { return c.run != nil } func (c *Command) Run(args []string) { c.run(args) } func (c *Command) Execute(args []string) { if c.isRoot { args = args[1:] } parser := opt.NewParser(args, c.opts, false) restArgs, err := parser.Parse() if err != nil { fmt.Println(err.Error()) c.ShowHelp() os.Exit(1) } if len(restArgs) > 0 { sc, ok := c.subcommands.Get(restArgs[0]) if ok { sc.Execute(restArgs[1:]) return } } helpOpt, ok := opt.Globals().GetBool("help") if ok && helpOpt.Value() { c.ShowHelp() return } if c.CanRun() { c.Run(restArgs) return } c.ShowHelp() }