feat(cmd): made error messaging closer to coreutils

This commit is contained in:
Lewis Wynne 2025-12-17 14:13:46 +00:00
parent 221d4cd921
commit 60d74e5ec1
4 changed files with 62 additions and 27 deletions

View file

@ -22,8 +22,8 @@ THE SOFTWARE.
package cmd
import (
"errors"
"fmt"
"os"
"strings"
"github.com/dgraph-io/badger/v4"
@ -32,11 +32,12 @@ import (
// delCmd represents the set command
var delCmd = &cobra.Command{
Use: "del KEY[@DB]",
Short: "Delete a key. Optionally specify a db.",
Aliases: []string{"delete", "rm", "remove"},
Args: cobra.ExactArgs(1),
RunE: del,
Use: "del KEY[@DB]",
Short: "Delete a key. Optionally specify a db.",
Aliases: []string{"delete", "rm", "remove"},
Args: cobra.ExactArgs(1),
RunE: del,
SilenceUsage: true,
}
func del(cmd *cobra.Command, args []string) error {
@ -47,6 +48,14 @@ func del(cmd *cobra.Command, args []string) error {
return err
}
exists, err := keyExists(store, args[0])
if err != nil {
return fmt.Errorf("cannot remove '%s': %v", args[0], err)
}
if !exists {
return fmt.Errorf("cannot remove '%s': No such key", args[0])
}
targetKey, err := formatKeyForPrompt(store, args[0])
if err != nil {
return err
@ -54,13 +63,12 @@ func del(cmd *cobra.Command, args []string) error {
if !force {
var confirm string
message := fmt.Sprintf("Are you sure you want to delete %q? (y/n)", targetKey)
message := fmt.Sprintf("remove %q: are you sure? (y/n)", targetKey)
fmt.Println(message)
if _, err := fmt.Scanln(&confirm); err != nil {
return err
return fmt.Errorf("cannot remove '%s': %v", args[0], err)
}
if strings.ToLower(confirm) != "y" {
fmt.Fprintf(os.Stderr, "Did not delete %q\n", targetKey)
return nil
}
}
@ -70,7 +78,10 @@ func del(cmd *cobra.Command, args []string) error {
readonly: false,
sync: false,
transact: func(tx *badger.Txn, k []byte) error {
return tx.Delete(k)
if err := tx.Delete(k); errors.Is(err, badger.ErrKeyNotFound) {
return nil
}
return fmt.Errorf("cannot remove '%s': %v", args[0], err)
},
}
@ -82,6 +93,27 @@ func init() {
rootCmd.AddCommand(delCmd)
}
func keyExists(store *Store, arg string) (bool, error) {
var notFound bool
trans := TransactionArgs{
key: arg,
readonly: true,
sync: false,
transact: func(tx *badger.Txn, k []byte) error {
if _, err := tx.Get(k); errors.Is(err, badger.ErrKeyNotFound) {
notFound = true
return nil
} else {
return err
}
},
}
if err := store.Transaction(trans); err != nil {
return false, err
}
return !notFound, nil
}
func formatKeyForPrompt(store *Store, arg string) (string, error) {
_, db, err := store.parse(arg, true)
if err != nil {

View file

@ -47,9 +47,10 @@ additional argument after the initial KEY being fetched.
For example:
pda set greeting 'Hello, {{ .NAME }}!'
pda get greeting NAME=World`,
Aliases: []string{"g"},
Args: cobra.MinimumNArgs(1),
RunE: get,
Aliases: []string{"g"},
Args: cobra.MinimumNArgs(1),
RunE: get,
SilenceUsage: true,
}
func get(cmd *cobra.Command, args []string) error {
@ -73,30 +74,30 @@ func get(cmd *cobra.Command, args []string) error {
}
if err := store.Transaction(trans); err != nil {
return err
return fmt.Errorf("cannot get '%s': %v", args[0], err)
}
includeSecret, err := cmd.Flags().GetBool("secret")
if err != nil {
return err
return fmt.Errorf("cannot get '%s': %v", args[0], err)
}
if meta&metaSecret != 0 && !includeSecret {
return fmt.Errorf("%q is marked secret; re-run with --secret to display it", args[0])
return fmt.Errorf("cannot get '%s': marked as secret, run with --secret", args[0])
}
binary, err := cmd.Flags().GetBool("include-binary")
if err != nil {
return err
return fmt.Errorf("cannot get '%s': %v", args[0], err)
}
run, err := cmd.Flags().GetBool("run")
if err != nil {
return err
return fmt.Errorf("cannot get '%s': %v", args[0], err)
}
noTemplate, err := cmd.Flags().GetBool("no-template")
if err != nil {
return err
return fmt.Errorf("cannot get '%s': %v", args[0], err)
}
if !noTemplate {
@ -106,7 +107,7 @@ func get(cmd *cobra.Command, args []string) error {
}
v, err = applyTemplate(v, substitutions)
if err != nil {
return err
return fmt.Errorf("cannot get '%s': %v", args[0], err)
}
}

View file

@ -71,7 +71,7 @@ func mv(cmd *cobra.Command, args []string) error {
if _, err := tx.Get(k); err == nil {
return fmt.Errorf("cannot move '%s': '%s' already exists > run with --force to overwrite", fromKey, toKey)
} else if err != badger.ErrKeyNotFound {
return err
return fmt.Errorf("cannot move '%s': %v", fromKey, err)
}
}
entry := badger.NewEntry(k, srcVal).WithMeta(srcMeta)

View file

@ -22,6 +22,7 @@ THE SOFTWARE.
package cmd
import (
"fmt"
"io"
"github.com/dgraph-io/badger/v4"
@ -42,9 +43,10 @@ For example:
'Hello, {{ default "World" .NAME }}' will default to World if NAME is blank.
'Hello, {{ require .NAME }}' will error if NAME is blank.
'{{ enum .NAME "Alice" "Bob" }}' allows only NAME=Alice or NAME=Bob.`,
Aliases: []string{"s"},
Args: cobra.RangeArgs(1, 2),
RunE: set,
Aliases: []string{"s"},
Args: cobra.RangeArgs(1, 2),
RunE: set,
SilenceUsage: true,
}
func set(cmd *cobra.Command, args []string) error {
@ -56,18 +58,18 @@ func set(cmd *cobra.Command, args []string) error {
} else {
bytes, err := io.ReadAll(cmd.InOrStdin())
if err != nil {
return err
return fmt.Errorf("cannot set '%s': %v", args[0], err)
}
value = bytes
}
secret, err := cmd.Flags().GetBool("secret")
if err != nil {
return err
return fmt.Errorf("cannot set '%s': %v", args[0], err)
}
ttl, err := cmd.Flags().GetDuration("ttl")
if err != nil {
return err
return fmt.Errorf("cannot set '%s': %v", args[0], err)
}
trans := TransactionArgs{