Initial grus version
This commit is contained in:
parent
69e919cd4e
commit
da2255557f
|
@ -0,0 +1,17 @@
|
|||
package main
|
||||
|
||||
import "os"
|
||||
|
||||
// getEnv will check if the the key exists, if it does then it'll
|
||||
// return the value otherwise it will return fallback string.
|
||||
func getEnv(key, fallback string) string {
|
||||
// We use os.LookupEnv instead of using os.GetEnv and checking
|
||||
// if the length equals 0 because environment variable can be
|
||||
// set and be of length 0. User could've set key="" which
|
||||
// means the variable was set but the length is 0.
|
||||
value, exists := os.LookupEnv(key)
|
||||
if !exists {
|
||||
value = fallback
|
||||
}
|
||||
return value
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"tildegit.org/andinus/grus/lexical"
|
||||
"tildegit.org/andinus/grus/search"
|
||||
"tildegit.org/andinus/grus/storage"
|
||||
)
|
||||
|
||||
func grus() {
|
||||
version := "v0.1.0"
|
||||
|
||||
// Early Check: If command was not passed then print usage and
|
||||
// exit. Later command & service both are checked, this check
|
||||
// is for version command. If not checked then running grus
|
||||
// without any args will fail because os.Args[1] will panic
|
||||
// the program & produce runtime error.
|
||||
if len(os.Args) == 1 || len(os.Args[1]) == 0 {
|
||||
printUsage()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Running just `grus` would've paniced the program here if
|
||||
// length of os.Args was not checked beforehand because there
|
||||
// would be no os.Args[1].
|
||||
switch os.Args[1] {
|
||||
case "version", "v", "-version", "--version", "-v":
|
||||
fmt.Printf("Grus %s\n", version)
|
||||
os.Exit(0)
|
||||
case "help", "-help", "--help", "-h":
|
||||
printUsage()
|
||||
os.Exit(0)
|
||||
case "init", "i":
|
||||
db := storage.Init()
|
||||
db.Conn.Close()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Initialize the database connection.
|
||||
db := storage.InitConn()
|
||||
defer db.Conn.Close()
|
||||
|
||||
word := os.Args[1]
|
||||
sorted := lexical.Sort(word)
|
||||
|
||||
out, err := search.Word(sorted, db)
|
||||
if err == sql.ErrNoRows {
|
||||
fmt.Println("Word not found in database.")
|
||||
return
|
||||
} else if err != nil {
|
||||
log.Fatalf("grus: Search failed :: %s", err)
|
||||
}
|
||||
fmt.Println(out)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// +build openbsd
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"tildegit.org/andinus/grus/storage"
|
||||
"tildegit.org/andinus/lynx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
unveil()
|
||||
grus()
|
||||
}
|
||||
|
||||
func unveil() {
|
||||
path := storage.GetDir()
|
||||
err := os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create directory: %s", path)
|
||||
}
|
||||
|
||||
paths := make(map[string]string)
|
||||
|
||||
paths[path] = "rwc"
|
||||
|
||||
err = lynx.UnveilPathsStrict(paths)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Block further unveil calls.
|
||||
err = unix.UnveilBlock()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
// +build !openbsd
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
grus()
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func printUsage() {
|
||||
fmt.Println("Usage: grus <word> / <command>")
|
||||
fmt.Println("\nCommands: ")
|
||||
fmt.Println(" help Print help")
|
||||
fmt.Println(" version Print Grus version")
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
framagit.org/andinus/grus v0.0.0-20200323142459-7a9fbe3c72e7 h1:+TuTHGVgEbsqFnjuWI064YfaCWImWndppHIZh/bMAhY=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200406113430-c6e801f48ba2 h1:Z9pPywZscwuw0ijrLEbTzW9lppFgBY4HDgbvoDnreQs=
|
||||
golang.org/x/sys v0.0.0-20200406113430-c6e801f48ba2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
tildegit.org/andinus/lynx v0.1.0 h1:7YjyF8h7MBGKRgQZT0j0I3uHRPf3mI2GMiDujXVlLS0=
|
||||
tildegit.org/andinus/lynx v0.1.0/go.mod h1:/PCNkKwfJ7pb6ziHa76a4gYp1R9S1Ro4ANjQwzSpBIk=
|
|
@ -0,0 +1,37 @@
|
|||
// +build linux netbsd openbsd freebsd dragonfly
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetDir returns grus data directory. Check if the user has set
|
||||
// GRUS_DIR, if not then check if XDG_DATA_HOME is set & if that is
|
||||
// not set then assume it to be the default value which is
|
||||
// $HOME/.local/share according to XDG Base Directory Specification.
|
||||
func GetDir() string {
|
||||
cacheDir := SysDir()
|
||||
|
||||
// Grus cache directory is cacheDir/grus.
|
||||
grusCacheDir := fmt.Sprintf("%s/%s", cacheDir,
|
||||
"grus")
|
||||
|
||||
return grusCacheDir
|
||||
}
|
||||
|
||||
// SysDir returns the system data directory, this is useful for unveil in
|
||||
// OpenBSD.
|
||||
func SysDir() string {
|
||||
cacheDir := os.Getenv("GRUS_DIR")
|
||||
if len(cacheDir) == 0 {
|
||||
cacheDir = os.Getenv("XDG_DATA_HOME")
|
||||
}
|
||||
if len(cacheDir) == 0 {
|
||||
cacheDir = fmt.Sprintf("%s/%s/%s", os.Getenv("HOME"),
|
||||
".local", "share")
|
||||
}
|
||||
|
||||
return cacheDir
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// initErr will log the error and close the database connection if
|
||||
// necessary.
|
||||
func initErr(db *DB, err error) {
|
||||
if db.Conn != nil {
|
||||
db.Conn.Close()
|
||||
}
|
||||
log.Fatalf("Initialization Error :: %s", err.Error())
|
||||
}
|
||||
|
||||
func initDB(db *DB) {
|
||||
var err error
|
||||
|
||||
db.Path = fmt.Sprintf("%s/grus.db", GetDir())
|
||||
|
||||
db.Conn, err = sql.Open("sqlite3", db.Path)
|
||||
if err != nil {
|
||||
log.Printf("storage/init.go: %s\n",
|
||||
"Failed to open database connection")
|
||||
initErr(db, err)
|
||||
}
|
||||
|
||||
sqlstmt := []string{
|
||||
`CREATE TABLE IF NOT EXISTS words (
|
||||
word TEXT PRIMARY KEY NOT NULL,
|
||||
sorted TEXT NOT NULL);`,
|
||||
`INSERT INTO words(word, lexical)
|
||||
values("grus", "grsu");`,
|
||||
}
|
||||
|
||||
// We range over statements and execute them one by one, this
|
||||
// is during initialization so it doesn't matter if it takes
|
||||
// few more ms. This way we know which statement caused the
|
||||
// program to fail.
|
||||
for _, s := range sqlstmt {
|
||||
stmt, err := db.Conn.Prepare(s)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("storage/init.go: %s\n",
|
||||
"failed to prepare statement")
|
||||
log.Println(s)
|
||||
initErr(db, err)
|
||||
}
|
||||
|
||||
_, err = stmt.Exec()
|
||||
stmt.Close()
|
||||
if err != nil {
|
||||
log.Printf("storage/init.go: %s\n",
|
||||
"failed to execute statement")
|
||||
log.Println(s)
|
||||
initErr(db, err)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// DB holds the database connection, mutex & path.
|
||||
type DB struct {
|
||||
Path string
|
||||
Mu *sync.RWMutex
|
||||
Conn *sql.DB
|
||||
}
|
||||
|
||||
// Init initializes the database.
|
||||
func Init() *DB {
|
||||
db := DB{
|
||||
Mu: new(sync.RWMutex),
|
||||
}
|
||||
|
||||
initDB(&db)
|
||||
return &db
|
||||
}
|
||||
|
||||
// InitConn initializes database connection.
|
||||
func InitConn() *DB {
|
||||
var err error
|
||||
db := DB{
|
||||
Mu: new(sync.RWMutex),
|
||||
}
|
||||
|
||||
db.Path = fmt.Sprintf("%s/grus.db", GetDir())
|
||||
|
||||
db.Conn, err = sql.Open("sqlite3", db.Path)
|
||||
if err != nil {
|
||||
log.Printf("storage/init.go: %s\n",
|
||||
"Failed to open database connection")
|
||||
initErr(&db, err)
|
||||
}
|
||||
|
||||
return &db
|
||||
}
|
Loading…
Reference in New Issue