package cmd import ( "fmt" "os" "go.fifitido.net/cmd/opt" ) type Command struct { Name string version string ShortDescription string LongDescription string Aliases []string Args []*Argument Opts opt.Set Subcommands Set Parent *Command run func(args []string) isRoot bool } func NewRoot(name string, version string, options ...Option) *Command { cmd := &Command{Name: name, version: version, 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) IsRoot() bool { return c.isRoot } func (c *Command) CommandPath() string { if c.Parent == nil { return "" } parentPath := c.Parent.CommandPath() if parentPath == "" { return c.Name } 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 len(args) > 0 { sc, ok := c.Subcommands.Get(args[0]) if ok { sc.Execute(args[1:]) return } } parser := opt.NewParser(args, c.Opts, false) restArgs, err := parser.Parse() if err != nil { fmt.Println(err.Error()) c.ShowHelp() os.Exit(1) } versionOpt, ok := opt.Globals().GetBool("version") if ok && versionOpt.Value() { c.ShowVersion() return } helpOpt, ok := opt.Globals().GetBool("help") if ok && helpOpt.Value() { c.ShowHelp() return } if c.CanRun() { c.Run(restArgs) return } c.ShowHelp() } func (c *Command) ShowVersion() { rootName := c.Root().Name fmt.Printf("%s %s\n", rootName, c.version) }