package cli import ( "context" "github.com/abelith/spellbook/internal/models" "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" "os" "strings" ) type Application interface { AddSpell(ctx context.Context, spell models.Spell) error GetSpell(ctx context.Context, spellName string) (models.Spell, error) GetSpells(ctx context.Context, query models.SearchQuery) ([]models.Spell, error) DeleteSpell(ctx context.Context, spellName string) error CastSpell(ctx context.Context, spellCast models.SpellCast) (models.CastResult, error) } func rootCmd(app Application) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() if len(args) < 1 { return listCommands(ctx, cmd, app) } return runCommand(ctx, app, args) } } func runCommand(ctx context.Context, app Application, args []string) error { spell, err := app.GetSpell(ctx, args[0]) if err != nil { return err } m := make(map[string]string, len(args[1:])) for _, pair := range args[1:] { keyVal := strings.Split(pair, "=") m[keyVal[0]] = keyVal[1] } _, err = app.CastSpell(ctx, models.SpellCast{ Spell: spell, Args: m, Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, }) if err != nil { return err } return nil } func listCommands(ctx context.Context, cmd *cobra.Command, app Application) error { spells, err := app.GetSpells(ctx, models.SearchQuery{}) if err != nil { return err } if len(spells) == 0 { cmd.Println("Spell book is empty. Try `spellbook add` to add your first spell") return nil } return printTable(cmd, spells) } func printTable(cmd *cobra.Command, spells []models.Spell) error { table := tablewriter.NewTable(cmd.OutOrStdout()) rows := make([][]string, 0, len(spells)) for _, spell := range spells { row := []string{ spell.Name, spell.Spell, spell.ShortDesc, strings.Join(spell.Tags, ", "), } rows = append(rows, row) } table.Header("Name", "Spell", "Short description", "Tags") _ = table.Bulk(rows) if err := table.Render(); err != nil { return err } return nil } func NewRootCmd(app Application) *cobra.Command { cmd := &cobra.Command{ Use: "spellbook", Short: "CLI tool to store, manage and execute command templates", Long: `Spellbook is a lightweight binary command manager written in Go. It allows you to save complex shell commands as parametrized templates (spells) and execute them instantly with custom arguments from anywhere in your terminal`, RunE: rootCmd(app), Args: cobra.ArbitraryArgs, } return cmd }