package main import ( "context" "fmt" "log" "os" "strings" "github.com/urfave/cli/v3" "go.etcd.io/bbolt" ) type controller struct { db *bbolt.DB tasksBucketName []byte } func newController(filename string) (controller, error) { db, err := bbolt.Open(filename, 0644, nil) if err != nil { return controller{}, fmt.Errorf("can't open database file '%s': %w", filename, err) } tasksBucketName := []byte("tasks") // Create the tasks bucket for the first time. From here on, // all transactions can assume this bucket exists. db.Update(func(tx *bbolt.Tx) error { _, err := tx.CreateBucket(tasksBucketName) if err != nil { return fmt.Errorf("cant' create tasks bucket: %w", err) } return nil }) return controller{db, tasksBucketName}, nil } func main() { ctrl, err := newController("tasks.db") if err != nil { log.Fatal(err) } cmd := &cli.Command{ Commands: []*cli.Command{ { Name: "add", Aliases: []string{"a"}, Usage: "add a task to the list", Action: func(ctx context.Context, cmd *cli.Command) error { args := cmd.Args().Slice() task := strings.Join(args, " ") return ctrl.cmdAdd(task) }, }, { Name: "do", Aliases: []string{"d"}, Usage: "complete a task on the list", Arguments: []cli.Argument{ &cli.IntArg{ Name: "taskIndex", }, }, Action: func(ctx context.Context, cmd *cli.Command) error { taskIndex := cmd.IntArg("taskIndex") // If taskIndex is 0, it's // likely missing; any other // non-positive value is a // deliberate // misconfiguration. if taskIndex <= 0 { return fmt.Errorf("invalid 'do' argument: %d", taskIndex) } return ctrl.cmdDo(taskIndex) }, }, { Name: "undo", Aliases: []string{"u"}, Usage: "reset a task on the list", Arguments: []cli.Argument{ &cli.IntArg{ Name: "taskIndex", }, }, Action: func(ctx context.Context, cmd *cli.Command) error { taskIndex := cmd.IntArg("taskIndex") if taskIndex <= 0 { return fmt.Errorf("invalid 'undo' argument: %d", taskIndex) } return ctrl.cmdUndo(taskIndex) }, }, { Name: "list", Aliases: []string{"l"}, Usage: "list pending tasks", Action: func(ctx context.Context, cmd *cli.Command) error { return ctrl.cmdList() }, }, { Name: "rm", Usage: "delete a task permanently", Arguments: []cli.Argument{ &cli.IntArg{ Name: "taskIndex", }, }, Action: func(ctx context.Context, cmd *cli.Command) error { taskIndex := cmd.IntArg("taskIndex") if taskIndex <= 0 { return fmt.Errorf("invalid 'undo' argument: %d", taskIndex) } return ctrl.cmdRm(taskIndex) }, }, }, } if err := cmd.Run(context.Background(), os.Args); err != nil { log.Fatal(err) } }