aboutsummaryrefslogtreecommitdiff
path: root/src/dedo.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/dedo.go')
-rw-r--r--src/dedo.go238
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))
+}