diff --git a/.gitignore b/.gitignore index ed2766c..0395e25 100644 --- a/.gitignore +++ b/.gitignore @@ -27,8 +27,8 @@ build # Binaries *.exe -boltbrowser -boltbrowser.* +/boltbrowser +/boltbrowser.* # Test Database test.db diff --git a/bolt_model.go b/internal/boltbrowser/bolt_model.go similarity index 99% rename from bolt_model.go rename to internal/boltbrowser/bolt_model.go index b0850c6..85775b6 100644 --- a/bolt_model.go +++ b/internal/boltbrowser/bolt_model.go @@ -1,4 +1,4 @@ -package main +package boltbrowser import ( "errors" diff --git a/cursor.go b/internal/boltbrowser/cursor.go similarity index 65% rename from cursor.go rename to internal/boltbrowser/cursor.go index b3b5aa4..b4711ec 100644 --- a/cursor.go +++ b/internal/boltbrowser/cursor.go @@ -1,4 +1,4 @@ -package main +package boltbrowser type Cursor struct { x int diff --git a/internal/boltbrowser/main.go b/internal/boltbrowser/main.go new file mode 100644 index 0000000..51acab3 --- /dev/null +++ b/internal/boltbrowser/main.go @@ -0,0 +1,79 @@ +package boltbrowser + +import ( + "fmt" + "os" + "time" + + "github.com/nsf/termbox-go" + "go.etcd.io/bbolt" +) + +var ProgramName = "boltbrowser" +var VersionNum = 2.0 + +var AppArgs Args +var databaseFiles []string +var db *bbolt.DB +var memBolt *BoltDB + +var currentFilename string + +const DefaultDBOpenTimeout = time.Second + +type Args struct { + DBOpenTimeout time.Duration + ReadOnly bool + NoValue bool +} + +func DefaultArgs() Args { + return Args{ + DBOpenTimeout: DefaultDBOpenTimeout, + } +} + +func Main(args Args, files []string) error { + // Set the global args. This is done to convert main package into a library with minimal changes. + AppArgs, databaseFiles = args, files + + var err error + err = termbox.Init() + if err != nil { + return err + } + defer termbox.Close() + style := defaultStyle() + termbox.SetOutputMode(termbox.Output256) + + for _, databaseFile := range databaseFiles { + currentFilename = databaseFile + db, err = bbolt.Open(databaseFile, 0600, &bbolt.Options{Timeout: AppArgs.DBOpenTimeout}) + if err == bbolt.ErrTimeout { + termbox.Close() + fmt.Printf("File %s is locked. Make sure it's not used by another app and try again\n", databaseFile) + os.Exit(1) + } else if err != nil { + if len(databaseFiles) > 1 { + mainLoop(nil, style) + continue + } else { + termbox.Close() + fmt.Printf("Error reading file: %q\n", err.Error()) + os.Exit(1) + } + } + + // First things first, load the database into memory + memBolt.refreshDatabase() + if AppArgs.ReadOnly { + // If we're opening it in readonly mode, close it now + db.Close() + } + + // Kick off the UI loop + mainLoop(memBolt, style) + defer db.Close() + } + return nil +} diff --git a/mainloop.go b/internal/boltbrowser/mainloop.go similarity index 97% rename from mainloop.go rename to internal/boltbrowser/mainloop.go index 7fda410..6d9b8b5 100644 --- a/mainloop.go +++ b/internal/boltbrowser/mainloop.go @@ -1,7 +1,7 @@ //go:build !windows // +build !windows -package main +package boltbrowser import ( "os" diff --git a/mainloop_windows.go b/internal/boltbrowser/mainloop_windows.go similarity index 97% rename from mainloop_windows.go rename to internal/boltbrowser/mainloop_windows.go index e8faddf..e286167 100644 --- a/mainloop_windows.go +++ b/internal/boltbrowser/mainloop_windows.go @@ -1,6 +1,6 @@ //go:build windows -package main +package boltbrowser // Windows doesn't support process backgrounding like *nix. // So we have a separate loop for it. diff --git a/screen.go b/internal/boltbrowser/screen.go similarity index 98% rename from screen.go rename to internal/boltbrowser/screen.go index 7bf5637..c8877cb 100644 --- a/screen.go +++ b/internal/boltbrowser/screen.go @@ -1,4 +1,4 @@ -package main +package boltbrowser import "github.com/nsf/termbox-go" diff --git a/screen_about.go b/internal/boltbrowser/screen_about.go similarity index 99% rename from screen_about.go rename to internal/boltbrowser/screen_about.go index 90a12cd..00dc24a 100644 --- a/screen_about.go +++ b/internal/boltbrowser/screen_about.go @@ -1,4 +1,4 @@ -package main +package boltbrowser import ( "fmt" diff --git a/screen_browser.go b/internal/boltbrowser/screen_browser.go similarity index 99% rename from screen_browser.go rename to internal/boltbrowser/screen_browser.go index aeb26cf..0f5dd25 100644 --- a/screen_browser.go +++ b/internal/boltbrowser/screen_browser.go @@ -1,4 +1,4 @@ -package main +package boltbrowser import ( "encoding/json" diff --git a/stringify.go b/internal/boltbrowser/stringify.go similarity index 97% rename from stringify.go rename to internal/boltbrowser/stringify.go index f7b1298..c2e5cfd 100644 --- a/stringify.go +++ b/internal/boltbrowser/stringify.go @@ -1,4 +1,4 @@ -package main +package boltbrowser import ( "encoding/binary" diff --git a/style.go b/internal/boltbrowser/style.go similarity index 96% rename from style.go rename to internal/boltbrowser/style.go index 26c4311..3d0e371 100644 --- a/style.go +++ b/internal/boltbrowser/style.go @@ -1,4 +1,4 @@ -package main +package boltbrowser import "github.com/nsf/termbox-go" diff --git a/main.go b/main.go index 9a95ed5..a9ba9e1 100644 --- a/main.go +++ b/main.go @@ -7,33 +7,20 @@ import ( "strings" "time" - "github.com/nsf/termbox-go" - "go.etcd.io/bbolt" + "github.com/br0xen/boltbrowser/pkg/boltbrowser" ) -var ProgramName = "boltbrowser" -var VersionNum = 2.0 - -var databaseFiles []string -var db *bbolt.DB -var memBolt *BoltDB - -var currentFilename string - -const DefaultDBOpenTimeout = time.Second - -var AppArgs struct { - DBOpenTimeout time.Duration - ReadOnly bool - NoValue bool +func main() { + args := boltbrowser.DefaultArgs() + files := parseArgs(&args) + err := boltbrowser.Main(args, files) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } } -func init() { - AppArgs.DBOpenTimeout = DefaultDBOpenTimeout - AppArgs.ReadOnly = false -} - -func parseArgs() { +func parseArgs(args *boltbrowser.Args) (databaseFiles []string) { var err error if len(os.Args) == 1 { printUsage(nil) @@ -51,10 +38,10 @@ func parseArgs() { key, val := pts[0], pts[1] switch key { case "-timeout": - AppArgs.DBOpenTimeout, err = time.ParseDuration(val) + args.DBOpenTimeout, err = time.ParseDuration(val) if err != nil { // See if we can successfully parse by adding a 's' - AppArgs.DBOpenTimeout, err = time.ParseDuration(val + "s") + args.DBOpenTimeout, err = time.ParseDuration(val + "s") } // If err is still not nil, print usage if err != nil { @@ -62,11 +49,11 @@ func parseArgs() { } case "-readonly", "-ro": if val == "true" { - AppArgs.ReadOnly = true + args.ReadOnly = true } case "-no-value": if val == "true" { - AppArgs.NoValue = true + args.NoValue = true } case "-help": printUsage(nil) @@ -77,9 +64,9 @@ func parseArgs() { // Single-word arguments switch parms[i] { case "-readonly", "-ro": - AppArgs.ReadOnly = true + args.ReadOnly = true case "-no-value": - AppArgs.NoValue = true + args.NoValue = true case "-help": printUsage(nil) default: @@ -87,58 +74,15 @@ func parseArgs() { } } } + return } func printUsage(err error) { if err != nil { fmt.Fprintf(os.Stderr, err.Error()) } - fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] \nOptions:\n", ProgramName) + fmt.Fprintf(os.Stderr, "Usage: boltbrowser [OPTIONS] \nOptions:\n") fmt.Fprintf(os.Stderr, " -timeout=duration\n DB file open timeout (default 1s)\n") fmt.Fprintf(os.Stderr, " -ro, -readonly \n Open the DB in read-only mode\n") fmt.Fprintf(os.Stderr, " -no-value \n Do not display a value in left pane\n") } - -func main() { - var err error - - parseArgs() - - err = termbox.Init() - if err != nil { - panic(err) - } - defer termbox.Close() - style := defaultStyle() - termbox.SetOutputMode(termbox.Output256) - - for _, databaseFile := range databaseFiles { - currentFilename = databaseFile - db, err = bbolt.Open(databaseFile, 0600, &bbolt.Options{Timeout: AppArgs.DBOpenTimeout}) - if err == bbolt.ErrTimeout { - termbox.Close() - fmt.Printf("File %s is locked. Make sure it's not used by another app and try again\n", databaseFile) - os.Exit(1) - } else if err != nil { - if len(databaseFiles) > 1 { - mainLoop(nil, style) - continue - } else { - termbox.Close() - fmt.Printf("Error reading file: %q\n", err.Error()) - os.Exit(1) - } - } - - // First things first, load the database into memory - memBolt.refreshDatabase() - if AppArgs.ReadOnly { - // If we're opening it in readonly mode, close it now - db.Close() - } - - // Kick off the UI loop - mainLoop(memBolt, style) - defer db.Close() - } -} diff --git a/pkg/boltbrowser/boltbrowser.go b/pkg/boltbrowser/boltbrowser.go new file mode 100644 index 0000000..aafa4d8 --- /dev/null +++ b/pkg/boltbrowser/boltbrowser.go @@ -0,0 +1,9 @@ +package boltbrowser + +import internal "github.com/br0xen/boltbrowser/internal/boltbrowser" + +type Args = internal.Args + +var DefaultArgs = internal.DefaultArgs + +var Main = internal.Main