Files
kvs-sh/main.go
ryyst bd73a1c477 feat: add export/import functionality for backup and migration
Implemented roadmap #4: Export/import functionality.

Features:
- export <file> <key1> [key2...] - Export specified keys to JSON
- export-list <keyfile> <output> - Bulk export from key list file
- import <file> - Import keys from JSON file
  --skip-existing (default) - Skip keys that already exist
  --overwrite - Overwrite existing keys

Export file format (v1.0):
{
  "version": "1.0",
  "entries": [
    {
      "key": "users/alice",
      "uuid": "...",
      "timestamp": 1234567890,
      "data": {...}
    }
  ]
}

The format preserves UUIDs and timestamps for audit trails.
Export shows progress with ✓/✗/⊘ symbols for success/fail/not-found.
Import checks for existing keys and respects skip/overwrite flags.

Use cases:
- Backup: export-list keys.txt backup.json
- Migration: import backup.json --overwrite
- Selective sync: export dest.json key1 key2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-05 23:57:25 +03:00

122 lines
2.3 KiB
Go

package main
import (
"fmt"
"os"
"strings"
"github.com/chzyer/readline"
)
// executeCommand executes a single command line
func (c *KVSClient) executeCommand(line string) bool {
parts := parseCommand(line)
if len(parts) == 0 {
return true
}
cmd := parts[0]
args := parts[1:]
switch cmd {
case "exit", "quit":
fmt.Println("Goodbye!")
return false
case "clear":
print("\033[H\033[2J")
case "help":
c.handleHelp(args)
case "connect":
c.handleConnect(args)
case "auth":
c.handleAuth(args)
case "profile":
c.handleProfile(args)
case "get":
c.handleGet(args)
case "put":
c.handlePut(args)
case "delete":
c.handleDelete(args)
case "meta":
c.handleMeta(args)
case "members":
c.handleMembers(args)
case "health":
c.handleHealth(args)
case "user":
if len(args) > 0 {
switch args[0] {
case "get":
c.handleUserGet(args[1:])
case "create":
c.handleUserCreate(args[1:])
default:
fmt.Println(red("Unknown user command:"), args[0])
fmt.Println("Type 'help' for available commands")
}
} else {
c.handleUserList(args)
}
case "group":
c.handleGroup(args)
case "export":
c.handleExport(args)
case "import":
c.handleImport(args)
case "export-list":
c.handleExportList(args)
case "batch", "source":
c.handleBatch(args, c.executeCommand)
default:
fmt.Println(red("Unknown command:"), cmd)
fmt.Println("Type 'help' for available commands")
}
return true
}
func main() {
client := NewKVSClient("http://localhost:8090")
// Load saved profiles
if config, err := LoadConfig(); err == nil {
client.syncConfigToClient(config)
}
// Setup readline
rl, err := readline.NewEx(&readline.Config{
Prompt: cyan("kvs> "),
HistoryFile: os.Getenv("HOME") + "/.kvs_history",
AutoComplete: completer,
InterruptPrompt: "^C",
EOFPrompt: "exit",
})
if err != nil {
panic(err)
}
defer rl.Close()
fmt.Println(magenta("KVS Interactive Shell"))
fmt.Println("Type 'help' for available commands")
if client.activeProfile != "" {
fmt.Println(green("Active profile:"), client.activeProfile)
}
fmt.Println()
for {
line, err := rl.Readline()
if err != nil {
break
}
line = strings.TrimSpace(line)
if line == "" {
continue
}
if !client.executeCommand(line) {
return
}
}
}