102 lines
2.0 KiB
Go
Executable File
102 lines
2.0 KiB
Go
Executable File
package notes
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"local/notes-server/filetree"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
type searcher struct {
|
|
patterns []*regexp.Regexp
|
|
}
|
|
|
|
func newSearcher(phrase string) (*searcher, error) {
|
|
phrases := strings.Split(phrase, " ")
|
|
patterns := make([]*regexp.Regexp, 0)
|
|
for _, phrase := range phrases {
|
|
if len(phrase) == 0 {
|
|
continue
|
|
}
|
|
pattern, err := regexp.Compile("(?i)" + phrase)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
patterns = append(patterns, pattern)
|
|
}
|
|
if len(patterns) < 1 {
|
|
return nil, errors.New("no search specified")
|
|
}
|
|
return &searcher{
|
|
patterns: patterns,
|
|
}, nil
|
|
}
|
|
|
|
func (s *searcher) matches(input []byte) bool {
|
|
for _, pattern := range s.patterns {
|
|
if !pattern.Match(input) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (n *Notes) Search(phrase string) (string, error) {
|
|
searcher, err := newSearcher(phrase)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
files := filetree.NewFiles()
|
|
err = filepath.Walk(n.root,
|
|
func(walked string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !info.Mode().IsRegular() {
|
|
return nil
|
|
}
|
|
if size := info.Size(); size < 1 || size > (5*1024*1024) {
|
|
return nil
|
|
}
|
|
ok, err := searcher.file(walked)
|
|
if err != nil && err.Error() == "bufio.Scanner: token too long" {
|
|
err = nil
|
|
}
|
|
if err != nil {
|
|
log.Printf("failed to scan %v: %v", walked, err)
|
|
} else if ok {
|
|
p := filetree.NewPathFromLocal(path.Dir(walked))
|
|
files.Push(p, info)
|
|
}
|
|
return err
|
|
},
|
|
)
|
|
return filetree.Paths(*files).List(true), err
|
|
}
|
|
|
|
func (searcher *searcher) file(file string) (bool, error) {
|
|
if d := path.Base(path.Dir(file)); strings.HasPrefix(d, ".") && strings.HasSuffix(d, ".attachments") {
|
|
return false, nil
|
|
}
|
|
if strings.Contains(file, "/.git/") {
|
|
return false, nil
|
|
}
|
|
f, err := os.Open(file)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
defer f.Close()
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
if searcher.matches(scanner.Bytes()) {
|
|
return true, scanner.Err()
|
|
}
|
|
}
|
|
return false, scanner.Err()
|
|
}
|