Skip to content

Commit e806ecb

Browse files
authored
Merge pull request #25 from pythonhacker/issue-10-search-multiple
Issue 10 search multiple
2 parents e879b0e + 3624934 commit e806ecb

File tree

4 files changed

+141
-28
lines changed

4 files changed

+141
-28
lines changed

README.md

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,38 +69,39 @@ The binary will be installed in `/usr/local/bin` folder.
6969
Usage
7070
=====
7171

72-
$ ./varuh -h
72+
$ varuh -h
7373
usage: varuh [-h|--help] [-I|--init "<value>"] [-d|--decrypt "<value>"]
7474
[-C|--clone "<value>"] [-R|--remove "<value>"] [-U|--use-db
75-
"<value>"] [-f|--find "<value>"] [-E|--edit "<value>"]
76-
[-l|--list-entry "<value>"] [-x|--export "<value>"] [-e|--encrypt]
77-
[-A|--add] [-p|--path] [-a|--list-all] [-g|--genpass] [-s|--show]
78-
[-c|--copy] [-y|--assume-yes] [-v|--version]
75+
"<value>"] [-E|--edit "<value>"] [-l|--list-entry "<value>"]
76+
[-x|--export "<value>"] [-f|--find "<value>" [-f|--find "<value>"
77+
...]] [-e|--encrypt] [-A|--add] [-p|--path] [-a|--list-all]
78+
[-g|--genpass] [-s|--show] [-c|--copy] [-y|--assume-yes]
79+
[-v|--version]
7980

8081
Password manager for the command line for Unix like operating
8182
systems
8283

8384
Options:
8485

85-
-h --help Print help information
86-
-I --init <path> Initialize a new database
87-
-d --decrypt <path> Decrypt password database
88-
-C --clone <id> Clone an entry with <id>
89-
-R --remove <id> Remove an entry with <id> or <id-range>
90-
-U --use-db <path> Set <path> as active database
91-
-f --find <term> Search entries with <term>
92-
-E --edit <id> Edit entry by <id>
93-
-l --list-entry <id> List entry by <id>
94-
-x --export <filename> Export all entries to <filename>
95-
-e --encrypt Encrypt the current database
96-
-A --add Add a new entry
97-
-p --path Show current database path
98-
-a --list-all List all entries in current database
99-
-g --genpass Generate a strong password (length: 12 - 16)
100-
-s --show Show passwords when listing entries
101-
-c --copy Copy password to clipboard
102-
-y --assume-yes Assume yes to actions requiring confirmation
103-
-v --version Show version information and exit
86+
-h --help Print help information
87+
-I --init <path> Initialize a new database
88+
-d --decrypt <path> Decrypt password database
89+
-C --clone <id> Clone an entry with <id>
90+
-R --remove <id> Remove an entry with <id> or <id-range>
91+
-U --use-db <path> Set <path> as active database
92+
-E --edit <id> Edit entry by <id>
93+
-l --list-entry <id> List entry by <id>
94+
-x --export <filename> Export all entries to <filename>
95+
-f --find <t1> <t2> ... Search entries with terms
96+
-e --encrypt Encrypt the current database
97+
-A --add Add a new entry
98+
-p --path Show current database path
99+
-a --list-all List all entries in current database
100+
-g --genpass Generate a strong password (length: 12 - 16)
101+
-s --show Show passwords when listing entries
102+
-c --copy Copy password to clipboard
103+
-y --assume-yes Assume yes to actions requiring confirmation
104+
-v --version Show version information and exit
104105

105106

106107
AUTHORS
@@ -441,6 +442,25 @@ An entry can be searched on its title, username, URL or notes. Search is case-in
441442
Modified: 2021-21-25 15:09:51
442443
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
443444

445+
446+
## To search using multiple terms
447+
448+
The `-f` option supports multiple terms, so you can specify this more than one time to narrow a search down to a specific entry.
449+
450+
$ varuh -f google -f anand
451+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
452+
ID: 8
453+
Title: Google account
454+
455+
URL:
456+
Password: **********
457+
Notes:
458+
Modified: 2021-21-25 15:02:50
459+
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
460+
461+
$ varuh -f google -f priya
462+
Entry for "google priya" not found
463+
444464
## To list all entries
445465

446466
To list all entries, use the option `-a`.

actions.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,12 +511,15 @@ func findCurrentEntry(term string) error {
511511

512512
var err error
513513
var entries []Entry
514+
var terms []string
514515

515516
if err = checkActiveDatabase(); err != nil {
516517
return err
517518
}
518519

519-
err, entries = searchDatabaseEntry(term)
520+
terms = strings.Split(term, " ")
521+
522+
err, entries = searchDatabaseEntries(terms, "AND")
520523
if err != nil || len(entries) == 0 {
521524
fmt.Printf("Entry for query \"%s\" not found\n", term)
522525
return err

db.go

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ func addNewDatabaseEntry(title, userName, url, passwd, notes string, customEntri
229229

230230
err, db = openActiveDatabase()
231231
if err == nil && db != nil {
232-
// result := db.Debug().Create(&entry)
232+
// result := db.Debug().Create(&entry)
233233
result := db.Create(&entry)
234234
if result.Error == nil && result.RowsAffected == 1 {
235235
// Add custom fields if given
@@ -341,6 +341,73 @@ func searchDatabaseEntry(term string) (error, []Entry) {
341341

342342
}
343343

344+
// Union of two entry arrays
345+
func union(entry1 []Entry, entry2 []Entry) []Entry {
346+
347+
m := make(map[int]bool)
348+
349+
for _, item := range entry1 {
350+
m[item.ID] = true
351+
}
352+
353+
for _, item := range entry2 {
354+
if _, ok := m[item.ID]; !ok {
355+
entry1 = append(entry1, item)
356+
}
357+
}
358+
359+
return entry1
360+
}
361+
362+
// Intersection of two entry arrays
363+
func intersection(entry1 []Entry, entry2 []Entry) []Entry {
364+
365+
var common []Entry
366+
367+
m := make(map[int]bool)
368+
369+
for _, item := range entry1 {
370+
m[item.ID] = true
371+
}
372+
373+
for _, item := range entry2 {
374+
if _, ok := m[item.ID]; ok {
375+
common = append(common, item)
376+
}
377+
}
378+
379+
return common
380+
}
381+
382+
// Search database for the given terms and returns matches according to operator
383+
func searchDatabaseEntries(terms []string, operator string) (error, []Entry) {
384+
385+
var err error
386+
var finalEntries []Entry
387+
388+
for idx, term := range terms {
389+
var entries []Entry
390+
391+
err, entries = searchDatabaseEntry(term)
392+
if err != nil {
393+
fmt.Printf("Error searching for term: %s - \"%s\"\n", term, err.Error())
394+
return err, entries
395+
}
396+
397+
if idx == 0 {
398+
finalEntries = entries
399+
} else {
400+
if operator == "AND" {
401+
finalEntries = intersection(finalEntries, entries)
402+
} else if operator == "OR" {
403+
finalEntries = union(finalEntries, entries)
404+
}
405+
}
406+
}
407+
408+
return nil, finalEntries
409+
}
410+
344411
// Remove a given database entry
345412
func removeDatabaseEntry(entry *Entry) error {
346413

main.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"github.com/pythonhacker/argparse"
88
"os"
9+
"strings"
910
)
1011

1112
const VERSION = 0.3
@@ -86,13 +87,16 @@ func performAction(optMap map[string]interface{}) {
8687
"edit": WrapperMaxKryptStringFunc(editCurrentEntry),
8788
"init": initNewDatabase,
8889
"list-entry": WrapperMaxKryptStringFunc(listCurrentEntry),
89-
"find": WrapperMaxKryptStringFunc(findCurrentEntry),
9090
"remove": WrapperMaxKryptStringFunc(removeCurrentEntry),
9191
"clone": WrapperMaxKryptStringFunc(copyCurrentEntry),
9292
"use-db": setActiveDatabasePath,
9393
"export": exportToFile,
9494
}
9595

96+
stringListActionsMap := map[string]actionFunc{
97+
"find": WrapperMaxKryptStringFunc(findCurrentEntry),
98+
}
99+
96100
stringActions2Map := map[string]actionFunc2{
97101
"decrypt": decryptDatabase,
98102
}
@@ -146,6 +150,18 @@ func performAction(optMap map[string]interface{}) {
146150
}
147151
}
148152

153+
for key, mappedFunc := range stringListActionsMap {
154+
if len(*optMap[key].(*[]string)) > 0 {
155+
156+
var vals = *(optMap[key].(*[]string))
157+
// Convert to single string
158+
var singleVal = strings.Join(vals, " ")
159+
mappedFunc(singleVal)
160+
flag = true
161+
break
162+
}
163+
}
164+
149165
if flag {
150166
return
151167
}
@@ -171,7 +187,6 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} {
171187
{"C", "clone", "Clone an entry with <id>", "<id>", ""},
172188
{"R", "remove", "Remove an entry with <id> or <id-range>", "<id>", ""},
173189
{"U", "use-db", "Set <path> as active database", "<path>", ""},
174-
{"f", "find", "Search entries with <term>", "<term>", ""},
175190
{"E", "edit", "Edit entry by <id>", "<id>", ""},
176191
{"l", "list-entry", "List entry by <id>", "<id>", ""},
177192
{"x", "export", "Export all entries to <filename>", "<filename>", ""},
@@ -181,6 +196,14 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} {
181196
optMap[opt.Long] = parser.String(opt.Short, opt.Long, &argparse.Options{Help: opt.Help, Path: opt.Path})
182197
}
183198

199+
stringListOptions := []CmdOption{
200+
{"f", "find", "Search entries with terms", "<t1> <t2> ...", ""},
201+
}
202+
203+
for _, opt := range stringListOptions {
204+
optMap[opt.Long] = parser.StringList(opt.Short, opt.Long, &argparse.Options{Help: opt.Help, Path: opt.Path})
205+
}
206+
184207
boolOptions := []CmdOption{
185208
{"e", "encrypt", "Encrypt the current database", "", ""},
186209
{"A", "add", "Add a new entry", "", ""},

0 commit comments

Comments
 (0)