返回 DeepSeek-Reasonix
globset.go
根目录 / internal / fileutil / globset.go
1 package fileutil
2
3 import (
4 "path/filepath"
5 "strings"
6
7 "github.com/bmatcuk/doublestar/v4"
8 )
9
10 // GlobSet matches slash-normalized paths against include and exclude patterns.
11 // It centralizes doublestar semantics for callers that need consistent
12 // include/exclude filtering without shell expansion.
13 type GlobSet struct {
14 include []string
15 exclude []string
16 }
17
18 func NewGlobSet(include, exclude []string) (GlobSet, error) {
19 set := GlobSet{
20 include: normalizeGlobPatterns(include),
21 exclude: normalizeGlobPatterns(exclude),
22 }
23 for _, pattern := range append(append([]string(nil), set.include...), set.exclude...) {
24 if _, err := doublestar.Match(pattern, ""); err != nil {
25 return GlobSet{}, err
26 }
27 }
28 return set, nil
29 }
30
31 func (s GlobSet) Match(path string) bool {
32 path = NormalizeSlashPath(path)
33 included := len(s.include) == 0
34 for _, pattern := range s.include {
35 if MatchSlashGlob(path, pattern) {
36 included = true
37 break
38 }
39 }
40 if !included {
41 return false
42 }
43 for _, pattern := range s.exclude {
44 if MatchSlashGlob(path, pattern) {
45 return false
46 }
47 }
48 return true
49 }
50
51 func MatchSlashGlob(path, pattern string) bool {
52 path = NormalizeSlashPath(path)
53 pattern = NormalizeSlashPath(pattern)
54 if matched, _ := doublestar.Match(pattern, path); matched {
55 return true
56 }
57 if strings.HasPrefix(pattern, "**/") {
58 matched, _ := doublestar.Match(strings.TrimPrefix(pattern, "**/"), path)
59 return matched
60 }
61 return false
62 }
63
64 func NormalizeSlashPath(path string) string {
65 return filepath.ToSlash(filepath.Clean(path))
66 }
67
68 func normalizeGlobPatterns(patterns []string) []string {
69 out := make([]string, 0, len(patterns))
70 for _, pattern := range patterns {
71 pattern = strings.TrimSpace(pattern)
72 if pattern == "" {
73 continue
74 }
75 out = append(out, NormalizeSlashPath(pattern))
76 }
77 return out
78 }
79
79 lines GO