-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.go
76 lines (69 loc) · 2.34 KB
/
search.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package todofinder
import (
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"strings"
. "github.com/thomasxnguy/todofinder/error"
"path/filepath"
)
// SearchResult represent one result when parsing file in research of a pattern.
// It collect essential data to display to end-users.
type SearchResult struct {
FileName string `json:"file"`
Position int `json:"pos"`
Comment string `json:"com"`
error *Error
}
// ToString return a verbose message corresponding to the search result.
func (s *SearchResult) ToString() string {
return fmt.Sprintf("%s:%v:\n%s\n", s.FileName, s.Position, s.Comment)
}
// GetError return error in result search.
func (s *SearchResult) GetError() *Error {
return s.error
}
// ImportPkg returns details about the Go package named by the import path,
// interpreting local import paths relative to dir.
// If the path is a local import path naming a package that can be imported
// using a standard import path, the returned package will set p.ImportPath
// to that path.
func ImportPkg(path, dir string) (*build.Package, *Error) {
//TODO Optimisations can be done here
p, err := build.Import(path, dir, build.ImportComment)
if err != nil {
return nil, &Error{PACKAGE_NOT_FOUND, Params{"package": path}, err}
}
if p.IsCommand() {
return nil, &Error{NO_SOURCE, Params{"source": p.Name}, err}
}
return p, nil
}
// ExtractPattern extracts all the comment in all the .go files from a specific package
// and search for a specific pattern. Each occurrence produce a result that is sent in the channel.
// Termination occurs when sending error or nil element in the channel.
func ExtractPattern(p *build.Package, pattern string, resultChannel chan *SearchResult) {
for _, f := range p.GoFiles {
fname := filepath.Join(p.Dir, f)
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
if err != nil {
resultChannel <- &SearchResult{"", 0, "", &Error{SOURCE_NOT_READABLE, Params{"source": fname}, err}}
return
}
cmap := ast.NewCommentMap(fset, f, f.Comments)
for n, cgs := range cmap {
f := fset.File(n.Pos())
for _, cg := range cgs {
t := cg.Text()
if strings.Contains(t, pattern) {
resultChannel <- &SearchResult{fname, f.Position(cg.Pos()).Line, t, nil}
}
}
}
}
//End of function, nil object will terminate the routine
resultChannel <- nil
}