package cmd import ( "os" "path/filepath" "go.fifitido.net/cmd/opts" ) type Command struct { name string shortDescription string longDescription string aliases []string arguments []*Argument opts opts.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:] } if err := c.opts.Parse(args); err != nil { c.ShowHelp() return } if len(args) > 0 { sc, ok := c.subcommands.Get(args[0]) if ok { sc.Execute(args[1:]) return } // TODO: remove when done with option parsing if args[0] == "--help" { c.ShowHelp() return } } if c.CanRun() { c.Run(args) return } c.ShowHelp() }