diff options
Diffstat (limited to 'src/dedo.go')
-rw-r--r-- | src/dedo.go | 238 |
1 files changed, 236 insertions, 2 deletions
diff --git a/src/dedo.go b/src/dedo.go index 14bb1d3..a997b3d 100644 --- a/src/dedo.go +++ b/src/dedo.go @@ -25,6 +25,8 @@ import ( "unicode" "unicode/utf8" "unsafe" + + g "gobang" ) @@ -424,6 +426,22 @@ type CompactCommand struct { // owning the discovered key/value pair k/v. type walkFunc func(keys [][]byte, k, v []byte, seq uint64) error +type argsT struct{ + databasePath string + command string + allArgs []string + args []string + bucket []byte + key []byte + value []byte +} + +type commandT struct{ + name string + getopt func(argsT, io.Writer) (argsT, bool) + exec func(argsT, *DB, io.Reader, io.Writer) error +} + const ( @@ -550,6 +568,8 @@ var ( // // + ErrMissingKey = errors.New("missing key") + // ErrUsage is returned when a usage message was printed and the process // should simply exit with an error. ErrUsage = errors.New("usage") @@ -2054,8 +2074,9 @@ func (db *DB) close() error { func (db *DB) Begin(writable bool) (*Tx, error) { if writable { return db.beginRWTx() + } else { + return db.beginTx() } - return db.beginTx() } func (db *DB) beginTx() (*Tx, error) { @@ -4100,7 +4121,7 @@ func (s *TxStats) Sub(other *TxStats) TxStats { return diff } -func Main() { +func _Main() { m := NewMain() if err := m.Run(os.Args[1:]...); err == ErrUsage { os.Exit(2) @@ -5573,3 +5594,216 @@ Additional options include: Defaults to 64KB. `, "\n") } + +func noopGetopt(args argsT, _w io.Writer) (argsT, bool) { + return args, true +} + +func getGetopt(args argsT, w io.Writer) (argsT, bool) { + if len(args.args) < 1 { + fmt.Fprintf(w, "Missing KEY.\n") + return args, false + } + + args.key = []byte(args.args[0]) + return args, true +} + +func setGetopt(args argsT, w io.Writer) (argsT, bool) { + if len(args.args) < 1 { + fmt.Fprintf(w, "Missing KEY and VALUE.\n") + return args, false + } + + if len(args.args) < 2 { + fmt.Fprintf(w, "Missing VALUE.\n") + return args, false + } + + args.key = []byte(args.args[0]) + args.value = []byte(args.args[1]) + return args, true +} + +func checkExec(args argsT, db *DB, _r io.Reader, _w io.Writer) error { + return db.View(func(tx *Tx) error { + var errs error + for err := range tx.Check() { + errs = g.WrapErrors(errs, err) + } + return errs + }) +} + +func getExec(args argsT, db *DB, r io.Reader, w io.Writer) error { + return db.View(func(tx *Tx) error { + bucket := tx.Bucket(args.bucket) + if bucket == nil { + return ErrBucketNotFound + } + + value := bucket.Get(args.key) + if value == nil { + return ErrMissingKey + } + + fmt.Fprintf(w, "%s\n", string(value)) + return nil + }) +} + +func setExec(args argsT, db *DB, r io.Reader, w io.Writer) error { + return db.Update(func(tx *Tx) error { + bucket, err := tx.CreateBucketIfNotExists(args.bucket) + if err != nil { + return err + } + + return bucket.Put(args.key, args.value) + }) +} + +func listExec(args argsT, db *DB, r io.Reader, w io.Writer) error { + return db.View(func(tx *Tx) error { + if len(args.bucket) == 0 { + return tx.ForEach(func( + name []byte, + bucket *Bucket, + ) error { + fmt.Fprintf(w, "%s\n", string(name)) + return nil + }) + } + + bucket := tx.Bucket(args.bucket) + if bucket == nil { + return ErrBucketNotFound + } + + return bucket.ForEach(func(key []byte, value []byte) error { + fmt.Fprintf(w, "%s\t%s\n", string(key), string(value)) + return nil + }) + }) +} + +func usage(argv0 string, w io.Writer) { + fmt.Fprintf( + w, + "Usage: %s [-f FILE] [-b BUCKET] COMMAND [ARGUMENTS]\n", + argv0, + ) +} + +func getopt( + allArgs []string, + commandsMap map[string]commandT, + w io.Writer, +) (argsT, commandT, int) { + argv0 := allArgs[0] + argv := allArgs[1:] + fs := flag.NewFlagSet("", flag.ContinueOnError) + fs.Usage = func() {} + fs.SetOutput(w) + databasePath := fs.String( + "f", + "data.kv", + "The path to the key-value database file", + ) + bucket := fs.String( + "b", + "default", + "The name of the bucket that'll be operated on", + ) + if fs.Parse(argv) != nil { + usage(argv0, w) + return argsT{}, commandT{}, 2 + } + + subArgs := fs.Args() + if len(subArgs) == 0 { + fmt.Fprintf(w, "Missing COMMAND.\n") + usage(argv0, w) + return argsT{}, commandT{}, 2 + } + + args := argsT{ + databasePath: *databasePath, + command: subArgs[0], + allArgs: allArgs, + args: subArgs[1:], + bucket: []byte(*bucket), + } + + command := commandsMap[args.command] + if command.name == "" { + fmt.Fprintf(w, "Bad COMMAND: \"%s\".\n", args.command) + usage(argv0, w) + return argsT{}, commandT{}, 2 + } + + args, ok := command.getopt(args, w) + if !ok { + usage(argv0, w) + return argsT{}, commandT{}, 2 + } + + return args, command, 0 +} + +func runCommand( + args argsT, + command commandT, + stdin io.Reader, + stdout io.Writer, + stderr io.Writer, +) int { + db, err := Open(args.databasePath) + if err != nil { + fmt.Fprintln(stderr, err) + return 1 + } + defer db.Close() + + err = command.exec(args, db, stdin, stdout) + if err != nil { + fmt.Fprintln(stderr, err) + return 1 + } + + return 0 +} + +var commands = map[string]commandT{ + "check": commandT{ + name: "check", + getopt: noopGetopt, + exec: checkExec, + }, + "get": commandT{ + name: "get", + getopt: getGetopt, + exec: getExec, + }, + "set": commandT{ + name: "set", + getopt: setGetopt, + exec: setExec, + }, + "list": commandT{ + name: "list", + getopt: noopGetopt, + exec: listExec, + }, +} + + + +func Main() { + g.Init() + args, command, rc := getopt(os.Args, commands, os.Stderr) + if rc != 0 { + os.Exit(2) + } + os.Exit(runCommand(args, command, os.Stdin, os.Stdout, os.Stderr)) +} |