diff --git a/usha.nim b/usha.nim index 73f4847..b2ce2ac 100644 --- a/usha.nim +++ b/usha.nim @@ -7,28 +7,32 @@ import ushapkg/[db, logger] const programName = "usha" help = """ -hist: search your command-line history. +$1: search your command-line history. Usage: $1 init [-v] $1 clean [DAYS] - $1 update [-v] CMD + $1 update [-v] CMD [-c CHECKSUM] $1 [DIR] [-n N] [-tvrs SEARCHSTRING] Options: DIR Directory to search within. - CMD Insert command into database. - DAYS Number of days of history to preserve. [default: 60] + CMD Insert command into database. + DAYS Number of days of history to preserve. [default: 60] -n N Retrieve the N most common commands. [default: 5] -s SEARCHSTRING Search for commands containing a string. -t Order by most recently entered. -v Verbose. -r Recurse current directory. + -c CHECKSUM Optional argument to update to prevent duplication. """ % programName -proc filter(stopWords: HashSet[string], cmd: string): bool = +proc filter(ignorePath, cmd: string): bool = ## Verify that a command is not 0-length and is not in the ignore ## list. + if not existsFile(ignorePath): + return true + let stopWords = toSeq(lines(ignorePath)).toSet case cmd of "": false @@ -57,15 +61,32 @@ proc historyInit() {.raises: [].} = except ValueError: quit "Unknown failure during database initialization." -proc historyUpdate(cwd, cmd: string, stopWords: HashSet[string]) {.raises: [].} = - if stopWords.filter(cmd): +proc historyUpdate(args: Table[string, docopt.Value]) {.raises: [].} = + const + ignoreFile = ".$1ignore" % programName + genericErrorMessage = "Unknown failure during database insertion." + + try: + let + cwd = getCurrentDir() + cmd = $args["CMD"] + checksum = if args["-c"]: $args["-c"] else: nil + ignorePath = getHomeDir() / ignoreFile + + if not ignorePath.filter(cmd): + log "Skipping update; value in stop words: " & cmd + elif not checksum.isNil and not dbChecksum(checksum): + log "Skipping update; checksum matches: " & checksum + else: + dbInsert(cwd, cmd, checksum) + + except DbError as e: try: - dbInsert(cwd, cmd) - except DbError as e: - try: - handleDbError(e, "Could not insert command into $1 database." % programName) - except ValueError: - quit "Unknown failure during database insertion." + handleDbError(e, "Could not insert command into $1 database." % programName) + except ValueError: + quit genericErrorMessage + except Exception, AssertionError, IOError: + quit genericErrorMessage proc historyClean(args: Table[string, docopt.Value]) {.raises: [] .} = try: @@ -110,31 +131,23 @@ proc historySearch(args: Table[string, docopt.Value]) {.raises: [].} = except ValueError: quit "Unknown error during database search." -when isMainModule: - var args = docopt(help) - +proc processArgs(args: Table[string, Value]) = if args["-v"]: setLogLevel vVerbose - discard dbOpen() - defer: dbClose() - if args["init"]: historyInit() - elif args["update"]: - var ignoreLines: HashSet[string] - const ignoreFile = ".ushaignore" - - let - ignorePath = getHomeDir() / ignoreFile - if existsFile(ignorePath): - ignoreLines = toSeq(lines(ignorePath)).toSet - - historyUpdate(getCurrentDir(), $args["CMD"], ignoreLines) - + historyUpdate(args) elif args["clean"]: historyClean(args) - else: historySearch(args) + +when isMainModule: + var args = docopt(help) + + discard dbOpen() + defer: dbClose() + + processArgs(args) diff --git a/usha.nimble b/usha.nimble index 85fd202..e03400c 100644 --- a/usha.nimble +++ b/usha.nimble @@ -1,6 +1,6 @@ # Package -version = "0.1.0" +version = "0.2" author = "Zach Smith" description = "untitled shell history application" license = "MIT" diff --git a/ushapkg/db.nim b/ushapkg/db.nim index 7974c7a..810472c 100644 --- a/ushapkg/db.nim +++ b/ushapkg/db.nim @@ -34,6 +34,15 @@ proc dbInit*() = db.exec sql"CREATE UNIQUE INDEX IF NOT EXISTS command_idx ON ? (cwd, cmd)", tableName db.exec sql"CREATE INDEX IF NOT EXISTS count_order_idx ON ? (count)", tableName db.exec sql"CREATE INDEX IF NOT EXISTS entered_order_idx ON ? (entered_on)", tableName + db.exec sql""" + CREATE TABLE IF NOT EXISTS checksum ( + hash VARCHAR(256) + )""" + db.exec sql""" + INSERT INTO checksum + SELECT "" WHERE NOT EXISTS ( + SELECT 1 FROM checksum + )""" type SearchResponse* = object cmd, count, timestamp: string @@ -142,13 +151,28 @@ proc dbSearch*( timestamp: if orderByTimeStamp: it[2] else: nil )) -proc dbInsert*(cwd, cmd: string) = +proc dbChecksum*(checksum: string): bool = + log "Checking checksum against value: " & checksum + + let currentValue = db.getValue sql""" + SELECT hash FROM checksum LIMIT 1 + """ + log "Current checksum value: " & currentValue + + currentValue != checksum + +proc dbInsert*(cwd, cmd, checksum: string) = db.exec sql""" INSERT OR REPLACE INTO ? (cwd, cmd, count) VALUES (?, ?, COALESCE( (SELECT count FROM ? WHERE cwd=? AND cmd=?), 0) + 1) """, tableName, cwd, cmd, tableName, cwd, cmd + if not checksum.isNil: + log "Updating checksum with value: " & checksum + db.exec sql""" + UPDATE checksum SET hash = ? + """, checksum proc dbClean*(days: string) = let