fork of https://github.com/sourcegraph/zoekt
1// package ignore provides helpers to support ignore-files similar to .gitignore
2package ignore
3
4import (
5 "bufio"
6 "io"
7 "strings"
8
9 "github.com/gobwas/glob"
10)
11
12var (
13 lineComment = "#"
14 IgnoreFile = ".sourcegraph/ignore"
15)
16
17type Matcher struct {
18 ignoreList []glob.Glob
19}
20
21// ParseIgnoreFile parses an ignore-file according to the following rules
22//
23// - each line represents a glob-pattern relative to the root of the repository
24// - for patterns without any glob-characters, a trailing ** is implicit
25// - lines starting with # are ignored
26// - empty lines are ignored
27func ParseIgnoreFile(r io.Reader) (matcher *Matcher, error error) {
28 var patterns []glob.Glob
29 scanner := bufio.NewScanner(r)
30 for scanner.Scan() {
31 line := strings.TrimSpace(scanner.Text())
32 // ignore empty lines
33 if line == "" {
34 continue
35 }
36 // ignore comments
37 if strings.HasPrefix(line, lineComment) {
38 continue
39 }
40 line = strings.TrimPrefix(line, "/")
41 // implicit ** for patterns without glob-characters
42 if !strings.ContainsAny(line, ".][*?") {
43 line += "**"
44 }
45 // with separators = '/', * becomes path-aware
46 pattern, err := glob.Compile(line, '/')
47 if err != nil {
48 return nil, err
49 }
50 patterns = append(patterns, pattern)
51 }
52 return &Matcher{ignoreList: patterns}, scanner.Err()
53}
54
55// Match returns true if path has a prefix in common with any item in m.ignoreList
56func (m *Matcher) Match(path string) bool {
57 if len(m.ignoreList) == 0 {
58 return false
59 }
60 for _, pattern := range m.ignoreList {
61 if pattern.Match(path) {
62 return true
63 }
64 }
65 return false
66}