-
Notifications
You must be signed in to change notification settings - Fork 0
/
filter.go
132 lines (110 loc) · 3.08 KB
/
filter.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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package file
import (
"io/ioutil"
"os"
"regexp"
"strings"
"github.com/ryanuber/go-glob"
)
var defaultRegexes = []*regexp.Regexp{
regexp.MustCompile(`\.git`),
regexp.MustCompile(`\.hg`),
regexp.MustCompile(`\.bzr`),
regexp.MustCompile(`\.svn`),
regexp.MustCompile(`_darcs`),
regexp.MustCompile(`CVS`),
regexp.MustCompile(`\.sublime-(project|workspace)`),
regexp.MustCompile(`\.DS_Store`),
regexp.MustCompile(`\.sass-cache`),
regexp.MustCompile(`Thumbs\.db`),
regexp.MustCompile(`desktop\.ini`),
regexp.MustCompile(`config.yml`),
regexp.MustCompile(`node_modules`),
}
var defaultGlobs = []string{}
// Filter matches filepaths to a list of patterns
type Filter struct {
rootDir string
regexps []*regexp.Regexp
globs []string
}
// NewFilter will create a new file path filter
func NewFilter(rootDir string, patterns []string, files []string) (Filter, error) {
filePatterns, err := filesToPatterns(files)
if err != nil {
return Filter{}, err
}
if !strings.HasSuffix(rootDir, "/") {
rootDir += "/"
}
regexps, globs := patternsToRegexpsAndGlobs(append(patterns, filePatterns...))
return Filter{
rootDir: rootDir,
regexps: regexps,
globs: globs,
}, nil
}
// Match will return true if the file path has matched a pattern in this filter
func (f Filter) Match(path string) bool {
if len(path) == 0 || !pathInProject(f.rootDir, path) {
return true
}
for _, regexp := range f.regexps {
if regexp.MatchString(path) {
return true
}
}
for _, pattern := range f.globs {
if glob.Glob(pattern, path) {
return true
}
}
return false
}
// filesToPatterns will load up external files and scrape patterns from them
func filesToPatterns(files []string) ([]string, error) {
patterns := []string{}
for _, name := range files {
file, err := os.Open(name)
if err != nil {
return patterns, err
}
defer file.Close()
var data []byte
if data, err = ioutil.ReadAll(file); err != nil {
return patterns, err
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSuffix(line, "\r") // remove windows carraige return
if len(line) > 0 && !strings.HasPrefix(line, "#") {
patterns = append(patterns, line)
}
}
}
return patterns, nil
}
// patternsToFiltersAndGlobs will take in string patterns and convert them to either
// regex patters or glob patterns so that they are handled in an expected manner.
func patternsToRegexpsAndGlobs(patterns []string) ([]*regexp.Regexp, []string) {
regexps := defaultRegexes
globs := defaultGlobs
for _, pattern := range patterns {
pattern = strings.TrimSpace(pattern)
//full regex
if strings.HasPrefix(pattern, "/") && strings.HasSuffix(pattern, "/") {
regexps = append(regexps, regexp.MustCompile(pattern[1:len(pattern)-1]))
continue
}
// if specifying a directory match everything below it
if strings.HasSuffix(pattern, "/") {
pattern += "*"
}
// The pattern will be scoped to root directory so it should match anything
// within that space
if !strings.HasPrefix(pattern, "*") {
pattern = "*" + pattern
}
globs = append(globs, pattern)
}
return regexps, globs
}