cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.77.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/discovery/glob.go

186lines · modecode

1package discovery
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "io/fs"
8 "log/slog"
9 "os"
10 "path/filepath"
11 "regexp"
12
13 "github.com/prometheus/common/model"
14
15 "github.com/cloudflare/pint/internal/git"
16 "github.com/cloudflare/pint/internal/parser"
17)
18
19func NewGlobFinder(patterns []string, filter git.PathFilter, schema parser.Schema, names model.ValidationScheme, allowedOwners []*regexp.Regexp) GlobFinder {
20 return GlobFinder{
21 patterns: patterns,
22 filter: filter,
23 schema: schema,
24 names: names,
25 allowedOwners: allowedOwners,
26 }
27}
28
29type GlobFinder struct {
30 filter git.PathFilter
31 patterns []string
32 allowedOwners []*regexp.Regexp
33 schema parser.Schema
34 names model.ValidationScheme
35}
36
37func (f GlobFinder) Find() (entries []Entry, err error) {
38 paths := filePaths{}
39 for _, p := range f.patterns {
40 matches, err := filepath.Glob(p)
41 if err != nil {
42 return nil, fmt.Errorf("failed to expand file path pattern %s: %w", p, err)
43 }
44
45 for _, path := range matches {
46 if path == ".git" && isDir(path) {
47 slog.LogAttrs(context.Background(), slog.LevelDebug,
48 "Excluding git directory from glob results",
49 slog.String("path", path),
50 slog.String("glob", p),
51 )
52 continue
53 }
54
55 subpaths, err := findFiles(path)
56 if err != nil {
57 return nil, err
58 }
59 for _, subpath := range subpaths {
60 if !paths.hasPath(subpath.path) {
61 paths = append(paths, subpath)
62 }
63 }
64 }
65 }
66
67 if len(paths) == 0 {
68 return nil, errors.New("no matching files")
69 }
70
71 for _, fp := range paths {
72 if !f.filter.IsPathAllowed(fp.path) {
73 continue
74 }
75
76 fd, err := os.Open(fp.path)
77 if err != nil {
78 return nil, err
79 }
80 p := parser.NewParser(!f.filter.IsRelaxed(fp.target), f.schema, f.names)
81 el, err := readRules(fp.target, fp.path, fd, p, f.allowedOwners)
82 if err != nil {
83 fd.Close()
84 return nil, fmt.Errorf("invalid file syntax: %w", err)
85 }
86 fd.Close()
87 for _, e := range el {
88 e.State = Noop
89 if len(e.ModifiedLines) == 0 {
90 e.ModifiedLines = e.Rule.Lines.Expand()
91 }
92 entries = append(entries, e)
93 }
94 }
95
96 slog.LogAttrs(context.Background(), slog.LevelDebug, "Glob finder completed", slog.Int("count", len(entries)))
97 return entries, nil
98}
99
100func isDir(path string) bool {
101 info, err := os.Stat(path)
102 if err != nil {
103 return false
104 }
105 return info.IsDir()
106}
107
108type filePath struct {
109 path string
110 target string
111}
112
113type filePaths []filePath
114
115func (fps filePaths) hasPath(p string) bool {
116 for _, fp := range fps {
117 if fp.path == p {
118 return true
119 }
120 }
121 return false
122}
123
124func findFiles(path string) (paths filePaths, err error) {
125 target, err := filepath.EvalSymlinks(path)
126 if err != nil {
127 return nil, fmt.Errorf("%s is a symlink but target file cannot be evaluated: %w", path, err)
128 }
129
130 s, err := os.Stat(path)
131 if err != nil {
132 return nil, err
133 }
134
135 // nolint: exhaustive
136 switch {
137 case s.IsDir():
138 subpaths, err := walkDir(path)
139 if err != nil {
140 return nil, err
141 }
142 paths = append(paths, subpaths...)
143 default:
144 paths = append(paths, filePath{path: path, target: target})
145 }
146
147 return paths, nil
148}
149
150func walkDir(dirname string) (paths filePaths, err error) {
151 err = filepath.WalkDir(dirname,
152 func(path string, d fs.DirEntry, err error) error {
153 if err != nil {
154 return err
155 }
156
157 // nolint: exhaustive
158 switch d.Type() {
159 case fs.ModeDir:
160 return nil
161 default:
162 dest, err := filepath.EvalSymlinks(path)
163 if err != nil {
164 return fmt.Errorf("%s is a symlink but target file cannot be evaluated: %w", path, err)
165 }
166
167 s, err := os.Stat(dest)
168 if err != nil {
169 return err
170 }
171 if s.IsDir() {
172 subpaths, err := findFiles(dest)
173 if err != nil {
174 return err
175 }
176 paths = append(paths, subpaths...)
177 } else {
178 paths = append(paths, filePath{path: path, target: dest})
179 }
180 }
181
182 return nil
183 })
184
185 return paths, err
186}
187