package main import ( "errors" "fmt" "github.com/AlecAivazis/survey/v2" "github.com/spf13/cobra" "os" "path/filepath" ) const ( submitOp = "submit" delOp = "del" updateOp = "update" ) type ContribOptions struct { CmdName string Operation string // submit, delete, update Admin bool ExecPath string } func runContrib(opts *ContribOptions) error { var action func(*ContribOptions) error switch opts.Operation { case submitOp: action = submit case delOp: action = delete case updateOp: action = update } return action(opts) } func submit(opts *ContribOptions) error { var cmdName string var category string var shortDescription string var longDescription string _, defaultName := filepath.Split(opts.ExecPath) if err := survey.AskOne(&survey.Input{ Message: "New command's name:", Default: defaultName}, &cmdName); err != nil { return err } categories := []string{ "art", "social", "game", "utility", "misc", } var choice int if err := survey.AskOne(&survey.Select{ Message: "what category should this command be filed under?", Options: categories, }, &choice); err != nil { return err } category = categories[choice] fmt.Printf("DBG %#v\n", category) if err := survey.AskOne(&survey.Input{ Message: "What's a one line description of this command?", }, &shortDescription); err != nil { return err } if err := survey.AskOne(&survey.Editor{ Message: "Write a long description for this command. Try to include examples. If the short description is enough, you can just leave it blank though. Really it's whatever you want. I donno"}, &longDescription); err != nil { return nil } // TODO create pending row // TODO email me // TODO print confirmation return nil } func update(opts *ContribOptions) error { return nil } func delete(opts *ContribOptions) error { return nil } func rootCmd() *cobra.Command { var updateName string var delName string var admin bool rc := &cobra.Command{ Use: "contrib [path to executable]", Short: "Submit new commands to the town launcher", RunE: func(cmd *cobra.Command, args []string) error { // submit - requires path arg // update - requres path arg // delete - no arg needed if updateName != "" && delName != "" { return errors.New("-u and -d are mutually exclusive") } var cmdName string operation := "submit" if updateName != "" { operation = "update" cmdName = updateName } else if delName != "" { operation = "delete" cmdName = delName } if (operation == "update" || operation == "submit") && len(args) == 0 { return errors.New("path to executable required when submitting or updating") } if operation == "delete" && len(args) > 0 { return fmt.Errorf("no arguments expected when deleting; got %d", len(args)) } if len(args) > 1 { return fmt.Errorf("at most one argument is accepted; got %d", len(args)) } var execPath string if len(args) == 1 { execPath = args[0] } opts := &ContribOptions{ Operation: operation, Admin: admin, ExecPath: execPath, CmdName: cmdName, } return runContrib(opts) }, // TODO longer example } rc.Flags().StringVarP(&updateName, "update", "u", "", "Name of command to update") rc.Flags().StringVarP(&delName, "delete", "d", "", "Name of command to delete") rc.Flags().BoolVarP(&admin, "admin", "a", false, "admin level operations") return rc } func main() { if err := rootCmd().Execute(); err != nil { fmt.Fprintln(os.Stderr, err.Error()) os.Exit(1) } }