diff --git a/cmd_batch.go b/cmd_batch.go new file mode 100644 index 0000000..8e20571 --- /dev/null +++ b/cmd_batch.go @@ -0,0 +1,73 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +// handleBatch executes commands from a file +func (c *KVSClient) handleBatch(args []string, executor func(string) bool) { + if len(args) < 1 { + fmt.Println(red("Usage: batch [--continue-on-error]")) + fmt.Println(" source [--continue-on-error]") + return + } + + filename := args[0] + + file, err := os.Open(filename) + if err != nil { + fmt.Println(red("Error opening file:"), err) + return + } + defer file.Close() + + scanner := bufio.NewScanner(file) + lineNum := 0 + successCount := 0 + errorCount := 0 + skippedCount := 0 + + for scanner.Scan() { + lineNum++ + line := strings.TrimSpace(scanner.Text()) + + // Skip empty lines and comments + if line == "" || strings.HasPrefix(line, "#") { + skippedCount++ + continue + } + + // Execute the command + fmt.Printf(cyan("[%d]")+" %s\n", lineNum, line) + + // Block exit/quit commands in batch mode + parts := parseCommand(line) + if len(parts) > 0 && (parts[0] == "exit" || parts[0] == "quit") { + fmt.Println(yellow("Note: exit/quit ignored in batch mode")) + skippedCount++ + continue + } + + // Execute command + executor(line) + successCount++ + } + + if err := scanner.Err(); err != nil { + fmt.Println(red("Error reading file:"), err) + return + } + + // Print summary + fmt.Println() + fmt.Println(cyan("Batch execution complete:")) + fmt.Printf(" Total lines: %d\n", lineNum) + fmt.Printf(" Executed: %s\n", green(fmt.Sprintf("%d", successCount))) + fmt.Printf(" Skipped: %d (empty/comments)\n", skippedCount) + if errorCount > 0 { + fmt.Printf(" Errors: %s\n", red(fmt.Sprintf("%d", errorCount))) + } +} diff --git a/cmd_system.go b/cmd_system.go index b8a028a..dcce3ba 100644 --- a/cmd_system.go +++ b/cmd_system.go @@ -60,6 +60,11 @@ Group Management: group add-member - Add member to group group remove-member - Remove member from group +Batch Operations: + batch - Execute commands from file + source - Alias for batch + --continue-on-error - Continue execution even if commands fail + System: help - Show this help exit, quit - Exit shell diff --git a/main.go b/main.go index 5ac4e91..3bc4823 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,67 @@ import ( "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 "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") @@ -47,59 +108,8 @@ func main() { continue } - parts := parseCommand(line) - if len(parts) == 0 { - continue - } - - cmd := parts[0] - args := parts[1:] - - switch cmd { - case "exit", "quit": - fmt.Println("Goodbye!") + if !client.executeCommand(line) { return - case "clear": - print("\033[H\033[2J") - case "help": - client.handleHelp(args) - case "connect": - client.handleConnect(args) - case "auth": - client.handleAuth(args) - case "profile": - client.handleProfile(args) - case "get": - client.handleGet(args) - case "put": - client.handlePut(args) - case "delete": - client.handleDelete(args) - case "meta": - client.handleMeta(args) - case "members": - client.handleMembers(args) - case "health": - client.handleHealth(args) - case "user": - if len(args) > 0 { - switch args[0] { - case "get": - client.handleUserGet(args[1:]) - case "create": - client.handleUserCreate(args[1:]) - default: - fmt.Println(red("Unknown user command:"), args[0]) - fmt.Println("Type 'help' for available commands") - } - } else { - client.handleUserList(args) - } - case "group": - client.handleGroup(args) - default: - fmt.Println(red("Unknown command:"), cmd) - fmt.Println("Type 'help' for available commands") } } } diff --git a/utils.go b/utils.go index 8021ddd..bb36137 100644 --- a/utils.go +++ b/utils.go @@ -127,6 +127,8 @@ var completer = readline.NewPrefixCompleter( readline.PcItem("add-member"), readline.PcItem("remove-member"), ), + readline.PcItem("batch"), + readline.PcItem("source"), readline.PcItem("help"), readline.PcItem("exit"), readline.PcItem("quit"),