1
0
Fork 0

Prepare for next rewrite

This commit is contained in:
Andinus 2020-04-08 01:44:15 +05:30
parent 47d22337b3
commit 34adb3a7e6
Signed by: andinus
GPG Key ID: B67D55D482A799FD
16 changed files with 1 additions and 483 deletions

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -1,7 +0,0 @@
// +build !openbsd
package main
func main() {
grus()
}

View File

@ -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
View File

@ -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
View File

@ -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=

View File

@ -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.")

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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
}