Prepare for next rewrite
This commit is contained in:
parent
47d22337b3
commit
34adb3a7e6
|
@ -1,17 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
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)
|
||||
|
||||
anagrams, err := search.Anagrams(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)
|
||||
}
|
||||
for _, w := range anagrams {
|
||||
fmt.Println(w)
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// +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)
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
// +build !openbsd
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
grus()
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
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")
|
||||
}
|
3
go.mod
3
go.mod
|
@ -3,7 +3,6 @@ module tildegit.org/andinus/grus
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
golang.org/x/sys v0.0.0-20200406113430-c6e801f48ba2
|
||||
tildegit.org/andinus/lynx v0.1.0
|
||||
tildegit.org/andinus/lynx v0.2.0
|
||||
)
|
||||
|
|
3
go.sum
3
go.sum
|
@ -1,6 +1,3 @@
|
|||
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=
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import sqlite3
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='grus-add')
|
||||
parser.add_argument('-f', '--file', type=str, required=False,
|
||||
help='file containing list of strings')
|
||||
parser.add_argument('-w', '--word', type=str, required=False,
|
||||
help='file containing list of strings')
|
||||
parser.add_argument('-d', '--db', type=str, required=True,
|
||||
help='database file')
|
||||
args = parser.parse_args()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if args.file == None and args.word == None:
|
||||
print("-f or -w required")
|
||||
print("run grus-add --help to print help")
|
||||
sys.exit(1)
|
||||
|
||||
conn = sqlite3.connect(args.db)
|
||||
curs = conn.cursor()
|
||||
|
||||
stmt = """CREATE TABLE IF NOT EXISTS words (
|
||||
word TEXT PRIMARY KEY NOT NULL,
|
||||
sorted TEXT NOT NULL);"""
|
||||
curs.execute(stmt)
|
||||
conn.commit()
|
||||
|
||||
stmt = """INSERT INTO words(word, sorted)
|
||||
VALUES(?, ?);"""
|
||||
|
||||
if args.file != None:
|
||||
rows = []
|
||||
with open(args.file) as words:
|
||||
for word in words:
|
||||
word = word.strip()
|
||||
lexical = ''.join(sorted(word))
|
||||
rows.append((word, lexical))
|
||||
print(len(rows))
|
||||
sys.stdout.write('\x1b[1A')
|
||||
sys.stdout.write('\x1b[2K')
|
||||
curs.executemany(stmt, rows)
|
||||
|
||||
elif args.word != None:
|
||||
word = args.word.strip()
|
||||
lexical = ''.join(sorted(word))
|
||||
curs.execute(stmt, (word, lexical))
|
||||
|
||||
conn.commit()
|
||||
|
||||
curs.close()
|
||||
conn.close()
|
||||
|
||||
print("Database initialized.")
|
13
scripts/init
13
scripts/init
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Download the list of words.
|
||||
curl -o /tmp/words.txt \
|
||||
https://raw.githubusercontent.com/dwyl/english-words/master/words.txt
|
||||
|
||||
# Make the script executable.
|
||||
chmod +x grus-add
|
||||
|
||||
# Add those words to the database.
|
||||
./grus-add \
|
||||
-d $HOME/.local/share/grus/grus.db \
|
||||
-f /tmp/words.txt
|
|
@ -1,56 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
openbsdH="25a8dc77cda3d225c85d3f0cb318d01c17546c1c4a8c789a318f832ce1948bc3"
|
||||
|
||||
earlyCheck(){
|
||||
os=`uname`
|
||||
os=`echo $os | tr "[:upper:]" "[:lower:"]`
|
||||
|
||||
case $os in
|
||||
*openbsd* ) ;;
|
||||
*)
|
||||
echo "Pre-built binary not available for your os"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
cpu=`uname -m`
|
||||
cpu=`echo $cpu | tr "[:upper:]" "[:lower:"]`
|
||||
|
||||
case $cpu in
|
||||
*amd*64* | *x86*64* ) ;;
|
||||
*)
|
||||
echo "Pre-built binary not available for your cpu"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
getURL(){
|
||||
url="https://archive.org/download/grus-v0.1.0/grus-v0.1.0-$os-$cpu"
|
||||
}
|
||||
|
||||
printURL(){
|
||||
echo "You can get the Pre-built binary here:"
|
||||
echo "$url"
|
||||
echo
|
||||
echo "Run these commands to install it on your device."
|
||||
echo "# curl -L -o /usr/local/bin/grus $url"
|
||||
echo "# chmod +x /usr/local/bin/grus"
|
||||
echo
|
||||
echo "This is sha256 hash for grus built for: $os $cpu"
|
||||
case $os in
|
||||
*openbsd* )
|
||||
echo "$openbsdH"
|
||||
;;
|
||||
esac
|
||||
echo
|
||||
echo "Verify the hash by running sha256 on grus binary."
|
||||
echo "$ sha256 /usr/local/bin/grus"
|
||||
}
|
||||
|
||||
echo "Grus v0.1.0"
|
||||
echo
|
||||
earlyCheck
|
||||
getURL
|
||||
printURL
|
|
@ -1,35 +0,0 @@
|
|||
package search
|
||||
|
||||
import "tildegit.org/andinus/grus/storage"
|
||||
|
||||
// Anagrams will search for unjumbled words in database, given sorted
|
||||
// word along with all the anagrams.
|
||||
func Anagrams(sorted string, db *storage.DB) (anagrams []string, err error) {
|
||||
db.Mu.RLock()
|
||||
defer db.Mu.RUnlock()
|
||||
|
||||
stmt, err := db.Conn.Prepare("SELECT word FROM words WHERE sorted = ?")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
rows, err := stmt.Query(sorted)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var word string
|
||||
err = rows.Scan(&word)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
anagrams = append(anagrams, word)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package search
|
||||
|
||||
import "tildegit.org/andinus/grus/storage"
|
||||
|
||||
// Word will search for unjumbled words in database, given sorted word.
|
||||
func Word(sorted string, db *storage.DB) (word string, err error) {
|
||||
db.Mu.RLock()
|
||||
defer db.Mu.RUnlock()
|
||||
|
||||
stmt, err := db.Conn.Prepare("SELECT word FROM words WHERE sorted = ?")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
err = stmt.QueryRow(sorted).Scan(&word)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
// +build darwin
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetDir returns grus data directory. Default data directory on
|
||||
// macOS is $HOME/Library.
|
||||
func GetDir() string {
|
||||
cacheDir := fmt.Sprintf("%s/%s",
|
||||
os.Getenv("HOME"),
|
||||
"Library")
|
||||
|
||||
// Grus cache directory is cacheDir/grus
|
||||
grusCacheDir := fmt.Sprintf("%s/%s", cacheDir,
|
||||
"grus")
|
||||
|
||||
return grusCacheDir
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
// +build linux netbsd openbsd freebsd dragonfly
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetDir returns grus data directory. Check if the user has set
|
||||
// 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() (grusCacheDir string) {
|
||||
cacheDir := SysDir()
|
||||
|
||||
// Grus cache directory is cacheDir/grus.
|
||||
grusCacheDir = fmt.Sprintf("%s/%s", cacheDir,
|
||||
"grus")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SysDir returns the system data directory, this is useful for unveil in
|
||||
// OpenBSD.
|
||||
func SysDir() (cacheDir string) {
|
||||
cacheDir = os.Getenv("XDG_DATA_HOME")
|
||||
if len(cacheDir) == 0 {
|
||||
cacheDir = fmt.Sprintf("%s/%s/%s", os.Getenv("HOME"),
|
||||
".local", "share")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
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
Block a user