feat(VCS): auto-commit hooked up to all changeful commands

This commit is contained in:
Lewis Wynne 2025-12-18 20:57:54 +00:00
parent 63e2cc55a0
commit 9506a2b657
6 changed files with 112 additions and 14 deletions

View file

@ -43,18 +43,22 @@ var delDbCmd = &cobra.Command{
func delDb(cmd *cobra.Command, args []string) error {
store := &Store{}
var notFound errNotFound
path, err := store.FindStore(args[0])
if errors.As(err, &notFound) {
return fmt.Errorf("cannot delete-db '%s': %v", args[0], err)
}
dbName, err := store.parseDB(args[0], false)
if err != nil {
return fmt.Errorf("cannot delete-db '%s': %v", args[0], err)
}
var notFound errNotFound
path, err := store.FindStore(dbName)
if errors.As(err, &notFound) {
return fmt.Errorf("cannot delete-db '%s': %v", dbName, err)
}
if err != nil {
return fmt.Errorf("cannot delete-db '%s': %v", dbName, err)
}
interactive, err := cmd.Flags().GetBool("interactive")
if err != nil {
return fmt.Errorf("cannot delete-db '%s': %v", args[0], err)
return fmt.Errorf("cannot delete-db '%s': %v", dbName, err)
}
if interactive || config.Store.AlwaysPromptDelete {
@ -63,13 +67,17 @@ func delDb(cmd *cobra.Command, args []string) error {
var confirm string
if _, err := fmt.Scanln(&confirm); err != nil {
return fmt.Errorf("cannot delete-db '%s': %v", args[0], err)
return fmt.Errorf("cannot delete-db '%s': %v", dbName, err)
}
if strings.ToLower(confirm) != "y" {
return nil
}
}
return executeDeletion(path)
if err := executeDeletion(path); err != nil {
return err
}
msg := fmt.Sprintf("rm-db @%s", dbName)
return autoCommit(store, []string{dbName}, msg)
}
func executeDeletion(path string) error {

View file

@ -71,6 +71,7 @@ func del(cmd *cobra.Command, args []string) error {
return fmt.Errorf("cannot remove: No such key")
}
var processed []resolvedTarget
for _, target := range targets {
if interactive || config.Key.AlwaysPromptDelete {
var confirm string
@ -101,11 +102,27 @@ func del(cmd *cobra.Command, args []string) error {
if err := store.Transaction(trans); err != nil {
return err
}
processed = append(processed, target)
}
if len(processed) == 0 {
return nil
}
var dbs []string
var labels []string
for _, t := range processed {
spec, err := store.parseKey(t.full, true)
if err != nil {
return err
}
dbs = append(dbs, spec.DB)
labels = append(labels, t.display)
}
msg := fmt.Sprintf("rm %s", strings.Join(labels, ", "))
return autoCommit(store, dbs, msg)
}
func init() {
delCmd.Flags().BoolP("interactive", "i", false, "Prompt yes/no for each deletion")
delCmd.Flags().StringSliceP("glob", "g", nil, "Delete keys matching glob pattern (repeatable)")

View file

@ -142,17 +142,23 @@ func mv(cmd *cobra.Command, args []string) error {
}
if copy {
return nil
msg := fmt.Sprintf("cp %s -> %s", fromSpec.Display(), toSpec.Display())
return autoCommit(store, []string{fromSpec.DB, toSpec.DB}, msg)
}
return store.Transaction(TransactionArgs{
if err := store.Transaction(TransactionArgs{
key: fromRef,
readonly: false,
sync: false,
transact: func(tx *badger.Txn, k []byte) error {
return tx.Delete(k)
},
})
}); err != nil {
return err
}
msg := fmt.Sprintf("mv %s -> %s", fromSpec.Display(), toSpec.Display())
return autoCommit(store, []string{fromSpec.DB, toSpec.DB}, msg)
}
var (

View file

@ -165,7 +165,8 @@ func restore(cmd *cobra.Command, args []string) error {
}
fmt.Fprintf(cmd.ErrOrStderr(), "Restored %d entries into @%s\n", restored, dbName)
return nil
msg := fmt.Sprintf("restore @%s (%d entries)", dbName, restored)
return autoCommit(store, []string{dbName}, msg)
}
func restoreInput(cmd *cobra.Command) (io.Reader, io.Closer, error) {

View file

@ -26,6 +26,7 @@ import (
"fmt"
"io"
"strings"
"unicode/utf8"
"github.com/dgraph-io/badger/v4"
"github.com/spf13/cobra"
@ -118,7 +119,13 @@ func set(cmd *cobra.Command, args []string) error {
},
}
return store.Transaction(trans)
if err := store.Transaction(trans); err != nil {
return err
}
valSummary := summarizeValue(value)
msg := fmt.Sprintf("set %s: %s", spec.Display(), valSummary)
return autoCommit(store, []string{spec.DB}, msg)
}
func init() {
@ -127,3 +134,14 @@ func init() {
setCmd.Flags().DurationP("ttl", "t", 0, "Expire the key after the provided duration (e.g. 24h, 30m)")
setCmd.Flags().BoolP("interactive", "i", false, "Prompt before overwriting an existing key")
}
func summarizeValue(v []byte) string {
if !utf8.Valid(v) {
return "(binary)"
}
s := string(v)
if len(s) > 80 {
return s[:80] + "..."
}
return s
}

View file

@ -3,6 +3,7 @@ package cmd
import (
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"os"
@ -478,3 +479,50 @@ func restoreSnapshot(store *Store, path string, dbName string) error {
}
return nil
}
func autoCommit(store *Store, dbs []string, message string) error {
if !config.Git.AutoCommit {
return nil
}
repoDir, err := ensureVCSInitialized()
if err != nil {
return err
}
unique := make(map[string]struct{})
for _, db := range dbs {
if db == "" {
db = config.Store.DefaultStoreName
}
unique[db] = struct{}{}
}
for db := range unique {
if err := snapshotOrRemoveDB(store, repoDir, db); err != nil {
return err
}
}
if err := runGit(repoDir, "add", "snapshots"); err != nil {
return err
}
return runGit(repoDir, "commit", "--allow-empty", "-m", message)
}
func snapshotOrRemoveDB(store *Store, repoDir, db string) error {
_, err := store.FindStore(db)
var nf errNotFound
if errors.As(err, &nf) {
snapPath := filepath.Join(repoDir, "snapshots", fmt.Sprintf("%s.ndjson", db))
if rmErr := os.Remove(snapPath); rmErr != nil && !os.IsNotExist(rmErr) {
return rmErr
}
return nil
}
if err != nil {
return err
}
return snapshotDB(store, repoDir, db)
}