From 3ee5d4cc226a5e42522f499ca0a22e9dbf49f4d6 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Wed, 20 Sep 2017 17:12:17 -0500 Subject: [PATCH] Initial Commit --- .gitignore | 2 + README.md | 3 ++ helpers.go | 30 +++++++++++++ main.go | 108 ++++++++++++++++++++++++++++++++++++++++++++++ model.go | 76 ++++++++++++++++++++++++++++++++ model_bookmark.go | 23 ++++++++++ structs.go | 12 ++++++ 7 files changed, 254 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 helpers.go create mode 100644 main.go create mode 100644 model.go create mode 100644 model_bookmark.go create mode 100644 structs.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f694ba2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore the binary +mark diff --git a/README.md b/README.md new file mode 100644 index 0000000..925afd3 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +mark + +A cli/cui bookmark manager diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..342e591 --- /dev/null +++ b/helpers.go @@ -0,0 +1,30 @@ +package main + +// helpers.go contains some helper functions for manipulating/processing data +// that doesn't really fit in elsewhere + +// matchStringInSlice finds the closes match to 'ndl' in 'hay' +// It starts at the beginning of 'ndl' and matches letters in 'hay' until either +// we've matched the whole 'ndl' or there is only one result left +func matchStringInSlice(ndl string, hay []string) string { + var nextHay []string + + for i := range ndl { + for _, p := range hay { + if p[i] == ndl[i] { + nextHay = append(hay, p) + } + } + // If we get here and there is only one parameter left, return it + hay = nextHay + if len(nextHay) == 1 { + break + } + // Otherwise, loop + nextHay = []string{} + } + if len(hay) == 0 { + return "" + } + return hay[0] +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..a61643b --- /dev/null +++ b/main.go @@ -0,0 +1,108 @@ +package main + +import ( + "fmt" + "os" + + userConfig "github.com/br0xen/user-config" +) + +const AppName = "mark" +const DefDBName = AppName + ".db" + +var mdb *MarkDB +var cfg *userConfig.Config + +// Valid command line options +var validFlags []cliFlag + +func main() { + err := initialize() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // If no command line options are given, go into gui mode + if len(os.Args) > 1 { + fmt.Println(os.Args[1]) + if os.Args[1] == "-a" { + // Adding a new bookmark + } + } else { + // Enter cui mode + fmt.Println("Entering CUI Mode") + } +} + +// initialize sets up the application for general use +func initialize() error { + var err error + // Build the list of valid command line options + addValidFlag("-a", "add", []string{"Add a new bookmark"}) + addValidFlag("-h", "help", []string{"Print the usage (this message)"}) + addValidFlag("-n", "name", []string{ + "When adding/updating, specify the name you wish to give a bookmark.", + "When searching, specifiy the name of the bookmark(s) you're searching for.", + }) + addValidFlag("-t", "tag", []string{ + "Comma delimited tags", + "When adding/updating, specify the tags you wish to give a bookmark.", + "When searching, specifiy the name of the tags you're searching for.", + }) + addValidFlag("-u", "update", []string{"Update an existing bookmark"}) + + // Load the config + cfg, err = userConfig.NewConfig(AppName) + if err != nil { + fmt.Println(err.Error()) + fmt.Println("Creating new config") + cfg.Save() + } + // if dbdir isn't set, set it to the config directory + if cfg.Get("dbdir") == "" { + cfg.Set("dbdir", cfg.GetConfigPath()+"/") + } + // if dbname isn't set, set it to the default db name + if cfg.Get("dbname") == "" { + cfg.Set("dbname", DefDBName) + } + // Get a reference to the database + if mdb, err = NewDatabase(cfg.Get("dbdir"), cfg.Get("dbname")); err != nil { + fmt.Println("Error loading the database") + os.Exit(1) + } + return nil +} + +// Adds an option to the "validFlags" slice +func addValidFlag(flag, name string, desc []string) { + validFlags = append(validFlags, cliFlag{ + Flag: flag, + Name: name, + Description: desc, + }) +} + +func printUsage() { + help := []string{ + "mark is a tool for keeping your bookmarks organized", + "", + "Usage: ", + "\tmark", + "", + "If no arguments are given, we enter gui mode", + "", + "Valid arguments are:", + "", + } + for _, ln := range help { + fmt.Println(ln) + } + for _, v := range validFlags { + fmt.Println(v.Flag, "\t", v.Name) + for _, hv := range v.Description { + fmt.Println("\t", hv) + } + } +} diff --git a/model.go b/model.go new file mode 100644 index 0000000..de6da30 --- /dev/null +++ b/model.go @@ -0,0 +1,76 @@ +package main + +import ( + "errors" + + "github.com/br0xen/boltease" +) + +// model.go contains some basic database stuff + +// MarkDB is an abstraction of a boltease.DB (which is an abstraction of +// a bolt.DB) +type MarkDB struct { + db *boltease.DB + dbOpened int // Track how many 'open' requests are outstanding + path, filename string +} + +func NewDatabase(path, name string) (*MarkDB, error) { + if path[len(path)-1] != '/' { + path = path + "/" + } + mdb := MarkDB{ + path: path, + filename: name, + } + return &mdb, nil +} + +func (mdb *MarkDB) openDatabase() error { + mdb.dbOpened += 1 + if mdb.dbOpened == 1 { + // We actually need to open the DB + var err error + mdb.db, err = boltease.Create(mdb.path+mdb.filename, 0600, nil) + if err != nil { + return err + } + } + return nil +} + +func (mdb *MarkDB) closeDatabase() error { + mdb.dbOpened -= 1 + if mdb.dbOpened == 0 { + // Actually close the database + return mdb.db.CloseDB() + } + return nil +} + +func (mdb *MarkDB) initDatabase() error { + var err error + if err = mdb.openDatabase(); err != nil { + return err + } + defer mdb.closeDatabase() + + // Create the path to the bucket to store bookmarks + if err = mdb.db.MkBucketPath([]string{"bookmarks"}); err != nil { + return errors.New("Error creating 'bookmarks' bucket: " + err.Error()) + } + // Create the path to the bucket to store additional config + if err = mdb.db.MkBucketPath([]string{"config"}); err != nil { + return errors.New("Error creating 'config' bucket: " + err.Error()) + } + if err = mdb.db.SetInt([]string{"config"}, "lastIdx", 0); err != nil { + return errors.New("Error setting 'lastIdx' to 0: " + err.Error()) + } + return nil +} + +// getNextIndex returns the next +func (mdb *MarkDB) getNextIndex() int { + return 0 +} diff --git a/model_bookmark.go b/model_bookmark.go new file mode 100644 index 0000000..4475aff --- /dev/null +++ b/model_bookmark.go @@ -0,0 +1,23 @@ +package main + +import "time" + +type Bookmark struct { + Id int + Name string + Url string + Desc string + Tags []string + Created time.Time + LastUsed time.Time +} + +func NewBookmark(url string) *Bookmark { + // First, search for a bookmark with this same URL + // If we didn't find one, create a new bookmark struct + b := Bookmark{ + Id: 0, + Url: url, + } + return &b +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..7d578aa --- /dev/null +++ b/structs.go @@ -0,0 +1,12 @@ +package main + +// structs.go contains structs for types that don't warrant their own 'model' +// file. + +// A command line option, used to parse command lines +// and also to display the usage +type cliFlag struct { + Flag string + Name string + Description []string +}